# TextControl.Web: Adding a Block Navigation Panel

> This sample recreates the Block Navigation Panel from TX Text Control Words inside TextControl.Web. It adds a custom ribbon button, triggers PostBack events via JavaScript, queries merge blocks using a ServerTextControl, and populates a TreeView for block-level navigation.

> **Note:** This article is outdated and may no longer be accurate.

- **Author:** Bjoern Meyer
- **Published:** 2015-05-08
- **Modified:** 2026-07-17
- **Description:** This sample recreates the Block Navigation Panel from TX Text Control Words inside TextControl.Web. It adds a custom ribbon button, triggers PostBack events via JavaScript, queries merge blocks using a ServerTextControl, and populates a TreeView for block-level navigation.
- **3 min read** (598 words)
- **Tags:**
  - ASP.NET
  - GitHub
  - HTML5
- **Web URL:** https://www.textcontrol.com/blog/2015/05/08/textcontrolweb-adding-a-block-navigation-panel/
- **LLMs URL:** https://www.textcontrol.com/blog/2015/05/08/textcontrolweb-adding-a-block-navigation-panel/llms.txt
- **LLMs-Full URL:** https://www.textcontrol.com/blog/2015/05/08/textcontrolweb-adding-a-block-navigation-panel/llms-full.txt
- **GitHub Repository:** https://github.com/TextControl/Web.TextControl.BlockNavigationPanel

---

Since version X12 (22.0), TextControl.Web provides a fully programmable interface with ASP.NET *code-behind*, server-side classes and a client-side Javascript interface.

Based on both interfaces, we implemented a sample project (scroll to the bottom for the download) that shows the *Block Navigation Panel*, that has been introduced in the Windows version of *TX Text Control Words* - the template designer for TX Text Control Reporting.

[![TextControl.Web: Adding a block navigation panel](https://s1-www.textcontrol.com/assets/dist/blog/2015/05/08/a/assets/animation_navigation.webp "TextControl.Web: Adding a block navigation panel")](https://s1-www.textcontrol.com/assets/dist/blog/2015/05/08/a/assets/animation_navigation.webp)

This demo shows many important steps to customize the editor:

- Adding a button to the Ribbon bar
- Attaching code-behind code to that button
- Selecting ranges of text in TextControl.Web
- Use a *ServerTextControl* instance to get all merge blocks and fields
- Use jQuery to add and remove style classes to and from ribbon elements

Download the sample project and open it in Visual Studio 2012 or better. In the following article, the most important parts are explained.

The navigation panel itself is a simple DIV element with an AJAX *UpdatePanel*, a *TreeView* and a hidden *Button* that is used to start the PostBack action on the UpdatePanel.

```
<div id="navigationBar">
    <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>

    <asp:UpdatePanel ID="UpdatePanel1" runat="server">

        <ContentTemplate>

            <asp:Button ID="hiddenBtnUpdateNavigationPanel"
                runat="server"
                Text="Button"
                OnClick="hiddenBtnUpdateNavigationPanel_Click"
                style="display: none;"/>

            <h3>Block Navigation</h3>
            <img class="close"
                onclick="togglePanel();"
                src="images/cross.png" />

            <asp:TreeView style="clear: both;"
                ID="TreeView1"
                runat="server"
                AutoGenerateDataBindings="False"
                ShowLines="True"
                OnSelectedNodeChanged="TreeView1_SelectedNodeChanged" />

        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger
                ControlID="hiddenBtnUpdateNavigationPanel"
                EventName="Click" />
        </Triggers>
    </asp:UpdatePanel>
</div>
```

Due to the fact that the hidden button's *Click* event is triggered using Javascript, the event must be registered in the *Render* method:

```
protected override void Render(HtmlTextWriter writer)
{
    // register the hidden button event
    Page.ClientScript.RegisterForEventValidation(
        hiddenBtnUpdateNavigationPanel.UniqueID);
    base.Render(writer);
}
```

The following Javascript adds a new button to the existing Ribbon bar and attaches a *Click* event to the button. In this event, a PostBack is triggered on the hidden button:

```
function addButton() {
    sNavigationPanelBtn = \'<div class="ribbon-group" id="newGroup"> \
    <div class="ribbon-group-content"> \
    <div id="navigationPanelButton" class="ribbon-button ribbon-button-big"> \
    <div class="ribbon-button-big-image-container"> \
    <img src="images/mailmergefieldnavigation.png" \
    class="ribbon-button-big-image" /> \
    </div> \
    <div class="ribbon-button-big-label-container"> \
    <p class="ribbon-button-label">Block<br />Navigation</p> \
    </div> \
    </div> \
    </div> \
    <div class="ribbon-group-label-container"> \
    <p class="ribbon-group-label">Navigation</p> \
    </div></div>\';

    // add the new button and ribbon group using HTML
    document.getElementById(\'ribbonGroupView\').insertAdjacentHTML(
        \'beforebegin\', sNavigationPanelBtn);

    // force a post back on the invisible button
    document.getElementById("navigationPanelButton").addEventListener(
        "click",
        function () {
            togglePanel();
            __doPostBack(\'<%= hiddenBtnUpdateNavigationPanel.ClientID %>\', \'\');
        });
```

The function *togglePanel* toggles the visibility of the navigation panel, adds the CSS to the ribbon button that indicates that it is selected and sends a command to TextControl.Web to set the EditMode to ReadOnly when the navigation panel is open.

```
function togglePanel() {
    $("#navigationBar").toggle();

    if ($("#navigationBar").css("display") == "none") {
        $("#navigationPanelButton").removeClass("ribbon-button-selected");
        TXTextControl.sendCommand(TXTextControl.Command.SetEditMode,
            TXTextControl.EditMode.Edit);
    }
    else {
        $("#navigationPanelButton").addClass("ribbon-button-selected");
        TXTextControl.sendCommand(TXTextControl.Command.SetEditMode,
            TXTextControl.EditMode.ReadAndSelect);
    }
}
```

In code-behind, a *ServerTextControl* instance is used to get the merge blocks and fields in order to fill the TreeView recursively with an ordered list of all (nested) blocks:

```
private void updateNavigationPanel()
{
    List<MergeBlock> blocks;

    try
    {
        using (TXTextControl.ServerTextControl tx =
            new TXTextControl.ServerTextControl())
        {
            tx.Create();
            byte[] data = null;

            TextControl1.SaveText(out data,
                TXTextControl.Web.BinaryStreamType.InternalUnicodeFormat);
            tx.Load(data, TXTextControl.BinaryStreamType.InternalUnicodeFormat);

            blocks = MergeBlock.GetMergeBlocks(
                MergeBlock.GetBlockMarkersOrdered(tx), tx);
        }

        TreeView1.Nodes.Clear();
        fillTreeView(blocks);
        TreeView1.ExpandAll();
    }
    catch { }
}
```

When a node is selected, the current document is loaded into a temporary *ServerTextControl* to get the merge blocks. The selected block is then selected using the *Selection* property of TextControl.Web:

```
protected void TreeView1_SelectedNodeChanged(object sender, EventArgs e)
{
    List<MergeBlock> blocks;

    using (TXTextControl.ServerTextControl tx =
        new TXTextControl.ServerTextControl())
    {
        tx.Create();
        byte[] data = null;

        TextControl1.SaveText(out data,
            TXTextControl.Web.BinaryStreamType.InternalUnicodeFormat);
        tx.Load(data, TXTextControl.BinaryStreamType.InternalUnicodeFormat);

        blocks = MergeBlock.GetMergeBlocksFlattened(tx);
    }

    // select the selected block in the TextControl.Web
    foreach (MergeBlock block in blocks)
    {
        if (block.Name == TreeView1.SelectedValue)
        {
            TextControl1.Selection =
                new TXTextControl.Web.Selection(block.StartMarker.Start,
                    block.Length);
            break;
        }
    }
}
```

Download the sample from GitHub and test it on your own.

---

## About Bjoern Meyer

As CEO, Bjoern is the visionary behind our strategic direction and business development, bridging the gap between our customers and engineering teams. His deep passion for coding and web technologies drives the creation of innovative products. If you're at a tech conference, be sure to stop by our booth - you'll most likely meet Bjoern in person. With an advanced graduate degree (Dipl. Inf.) in Computer Science, specializing in AI, from the University of Bremen, Bjoern brings significant expertise to his role. In his spare time, Bjoern enjoys running, paragliding, mountain biking, and playing the piano.

- [LinkedIn](https://www.linkedin.com/in/bjoernmeyer/)
- [X](https://x.com/txbjoern)
- [GitHub](https://github.com/bjoerntx)

---

## Related Posts

- [ASP.NET MVC: Implementing a Simplistic, Custom Button Bar](https://www.textcontrol.com/blog/2017/03/13/aspnet-mvc-implementing-a-simplistic-custom-button-bar/llms.txt)
- [ASP.NET MVC: Adding Protected Sections to Documents](https://www.textcontrol.com/blog/2017/03/01/aspnet-mvc-adding-protected-sections-to-documents/llms.txt)
- [ASP.NET: Adding Electronic Signatures to Documents](https://www.textcontrol.com/blog/2016/10/12/aspnet-adding-electronic-signatures-to-documents/llms.txt)
- [MVC: Loading Files from the Backstage Menu](https://www.textcontrol.com/blog/2016/01/06/mvc-loading-files-from-the-backstage-menu/llms.txt)
- [MVC: Replace the File Menu with a Backstage View Menu](https://www.textcontrol.com/blog/2015/12/30/mvc-replace-the-file-menu-with-a-backstage-view-menu/llms.txt)
- [MVC: Replace the Ribbon Table Menu with a Quick Insert Table Drop-down](https://www.textcontrol.com/blog/2015/12/23/mvc-replace-the-ribbon-table-menu-with-a-quick-insert-table-drop-down/llms.txt)
- [MVC: Arrange a Docked Web.TextControl with a Custom Bar at the Top](https://www.textcontrol.com/blog/2015/12/18/mvc-arrange-a-docked-webtextcontrol-with-a-custom-bar-at-the-top/llms.txt)
- [MVC: Autosave and Restore Documents to and from the Local Browser Storage](https://www.textcontrol.com/blog/2015/12/14/mvc-autosave-and-restore-documents-to-and-from-the-local-browser-storage/llms.txt)
- [MVC: Loading and Saving Documents Through Controller HttpPost Methods](https://www.textcontrol.com/blog/2015/12/08/mvc-loading-and-saving-documents-through-controller-httppost-methods/llms.txt)
- [HTML5: Adding a Download Button to the Ribbon File Menu](https://www.textcontrol.com/blog/2015/10/22/html5-adding-a-download-button-to-the-ribbon-file-menu/llms.txt)
- [HTML5: Make Merge Field Lists Scrollable in the Ribbon Bar](https://www.textcontrol.com/blog/2015/10/16/html5-make-merge-field-lists-scrollable-in-the-ribbon-bar/llms.txt)
- [HTML5: Store Documents Using the Local Browser Storage](https://www.textcontrol.com/blog/2015/10/09/html5-store-documents-using-the-local-browser-storage/llms.txt)
- [HTML5: Saving Documents in an MVC Controller Method](https://www.textcontrol.com/blog/2015/10/01/html5-saving-documents-in-an-mvc-controller-method/llms.txt)
- [HTML5: Display and Handle FormCheckBox Fields](https://www.textcontrol.com/blog/2015/09/22/html5-display-and-handle-formcheckbox-fields/llms.txt)
- [Building a Touch-enabled Button Bar with Javascript](https://www.textcontrol.com/blog/2015/05/27/building-a-touch-enabled-button-bar-with-javascript/llms.txt)
- [TextControl.Web: Creating an MVC Application with Razor](https://www.textcontrol.com/blog/2015/05/12/textcontrolweb-creating-an-mvc-application-with-razor/llms.txt)
- [Web.TextControl: JQueryUI Alert Boxes and Javascript Events](https://www.textcontrol.com/blog/2015/04/20/webtextcontrol-jqueryui-alert-boxes-and-javascript-events/llms.txt)
- [Building a TX Text Control Project with GitHub Actions and the Text Control NuGet Feed](https://www.textcontrol.com/blog/2026/02/09/building-a-tx-text-control-project-with-github-actions-and-the-text-control-nuget-feed/llms.txt)
- [Creating an ASP.NET Core Web App with Docker Support and GitHub Packages](https://www.textcontrol.com/blog/2024/01/05/creating-an-asp-net-core-web-app-with-docker-support-and-github-packages/llms.txt)
- [Official TX Text Control .NET Sample Applications Are Now Hosted on GitHub](https://www.textcontrol.com/blog/2023/01/08/official-tx-text-control-net-sample-applications-are-now-hosted-on-github/llms.txt)
- [Preparing Projects for GitHub Actions](https://www.textcontrol.com/blog/2022/06/27/preparing-projects-for-github-actions/llms.txt)
- [Detect Toggle Button Changes Using a MutationObserver](https://www.textcontrol.com/blog/2021/11/11/detect-toggle-button-changes-using-a-mutationobserver/llms.txt)
- [Implementing Conditional Table Cell Colors with MailMerge](https://www.textcontrol.com/blog/2020/10/08/implementing-conditional-table-cell-colors-with-mailmerge/llms.txt)
- [Securing the WebSocketHandler Endpoint in ASP.NET](https://www.textcontrol.com/blog/2020/05/28/securing-the-websockethandler-endpoint-in-aspnet/llms.txt)
- [Creating an ASP.NET MVC DocumentViewer Application With Razor](https://www.textcontrol.com/blog/2020/01/01/creating-an-aspnet-mvc-documentviewer-application-with-razor/llms.txt)
