Products Technologies Demo Docs Blog Support Company

This blog post contains outdated information.

The cited code snippets may be workarounds, and be part of the official API in the meantime.

TextControl.Web: Adding a Block Navigation Panel

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. This demo shows many important steps to customize the editor:…

TextControl.Web: Adding a Block Navigation Panel

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.

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.

Stay in the loop!

Subscribe to the newsletter to receive the latest updates.

GitHub

Download and Fork This Sample on GitHub

We proudly host our sample code on github.com/TextControl.

Please fork and contribute.

Download ZIP

Open on GitHub

Open in Visual Studio

Requirements for this sample

  • Visual Studio 2012 or better
  • TX Text Control .NET Server (trial sufficient)

ASP.NET

Integrate document processing into your applications to create documents such as PDFs and MS Word documents, including client-side document editing, viewing, and electronic signatures.

ASP.NET Core
Angular
Blazor
JavaScript
React
  • Angular
  • Blazor
  • React
  • JavaScript
  • ASP.NET MVC, ASP.NET Core, and WebForms

Learn more Trial token Download trial

Related Posts

ASP.NETReportingGitHub

ASP.NET MVC: Implementing a Simplistic, Custom Button Bar

For some applications, the fully-featured ribbon bar might be too overloaded with features or the ribbon concept is not required in a project. Programmatically, all ribbon tabs, groups and buttons…


ASP.NETReportingGitHub

ASP.NET MVC: Adding Protected Sections to Documents

A SubTextPart object represents a user-defined range of text in a TX Text Control document. A SubTextPart is basically a range of text with a Name and an ID property to store additional…


ASP.NETReportingElectronic Signature

ASP.NET: Adding Electronic Signatures to Documents

An electronic signature is in many processes legally sufficient to prove an identity. According to the U.S. Federal ESIGN Act passed in 2000, an electronic signature is an: Electronic sound,…


ASP.NETGitHubHTML5

MVC: Loading Files from the Backstage Menu

Happy New Year, everybody! In the last blog entry, we showed how to replace the file menu with an MS Word-style backstage menu. This project shows how to load documents from a partial view in the…


ASP.NETGitHubHTML5

MVC: Replace the File Menu with a Backstage View Menu

Microsoft Word provides a very smart way to manage documents and related data such as metadata and personal information in a separate view: The backstage view. The ribbon bar contains commands for…