Word (RTF) Find and Replace

This demo shows how the Word Processing Document API allows you to find and replace text in the document.

Options
Find
Replace With
Find All
Replace All
File Format
Download
@model AspNetCoreDemos.OfficeFileAPI.WordRTFFindAndReplaceModel
@using DevExtreme.AspNet.Mvc

@using (Html.BeginForm("WordRTFFindAndReplaceExportTo", "ContentManipulation")) {
    @Html.HiddenFor(model => model.ActionToExec);

    <div class="demo-view-container">
        @await Html.PartialAsync("WordRTFPreviewPartial", Model.PreviewModel)
    </div>

    <script type="text/javascript">
        function UpdatePreview(action) {
            var txbFindValue = $("#Find").dxTextBox('instance').option('value');
            var txbReplaceValue = $("#Replace").dxTextBox('instance').option('value');
            var args = "Find=" + encodeURIComponent(txbFindValue) +
                "&Replace=" + encodeURIComponent(txbReplaceValue) +
                "&ActionToExec=" + encodeURIComponent(action);
            WordRTFPreview.Update(args);
            $("#ActionToExec").val(action);
        }
    </script>
    <div class="options">
        <div class="caption">Options</div>
        <div class="option">
            <div class="label">Find</div>
            @(Html.DevExtreme().TextBoxFor(m => m.Find).ID("Find"))
        </div>
        <div class="option">
            <div class="label">Replace With</div>
            @(Html.DevExtreme().TextBoxFor(m => m.Replace).ID("Replace"))
        </div>
        <div class="option-buttons clearfix" style="margin-bottom: 20px">
            @(Html.DevExtreme().Button()
                               .Text("Find All")
                               .Type(ButtonType.Default)
                               .StylingMode(ButtonStylingMode.Contained)
                               .OnClick("function(s) { UpdatePreview('find'); }")
            )
            @(Html.DevExtreme().Button()
                               .Text("Replace All")
                               .Type(ButtonType.Default)
                               .StylingMode(ButtonStylingMode.Contained)
                               .OnClick("function(s) { UpdatePreview('replace'); }")
                               .ElementAttr("style", "margin-left: 10px")
            )
        </div>
        @await Html.PartialAsync("WordRTFDocumentDownloaderPartial", Model)
    </div>
}
@model AspNetCoreDemos.OfficeFileAPI.WordRTFPreviewModel

<iframe id="previewFrame" src="@Url.Action(Model.PreviewDocumentAction, Model.ControllerName)" height="@Model.IFrameSize" class="demo-preview-border" style="width:100%;box-sizing:border-box"></iframe>

<script type="text/javascript">
    WordRTFPreview = {
        basePath: '@Url.Action(Model.PreviewDocumentAction, Model.ControllerName)',
        Update: function (param) {
            var iframeElementName = "previewFrame";
            var iframeElement = document.getElementById(iframeElementName);
            if (!iframeElement)
                return;
            var additionalParams = "&" + new Date().valueOf();
            if (param)
                additionalParams = param;
            iframeElement.src = this.basePath + "?" + additionalParams;
        }
    };
</script>
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;

namespace AspNetCoreDemos.OfficeFileAPI {
    public partial class ContentManipulationController : DocumentProcessingController {
        public ContentManipulationController(ILogger<ContentManipulationController> logger, IWebHostEnvironment hostingEnvironment)
            : base(logger, hostingEnvironment) {
        }
    }
}
using System;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using DevExpress.Office.Services;
using DevExpress.XtraRichEdit;
using DevExpress.XtraRichEdit.API.Native;
using DevExpress.Web.Office;

namespace AspNetCoreDemos.OfficeFileAPI {
    public partial class ContentManipulationController {
        const string findAndReplaceFilePath = "/Documents/Search.rtf";

        public IActionResult WordRTFFindAndReplace() {
            WordRTFFindAndReplaceModel model = new WordRTFFindAndReplaceModel();
            return View(model);
        }

        public IActionResult WordRTFPreviewFindAndReplace(WordRTFFindAndReplaceModel model) {
            Stream stream = ExecuteFindAndReplace(DocumentFormat.Html, model.Find, model.Replace, model.ActionToExec);
            return CreatePreviewResult(stream);
        }

        public IActionResult WordRTFFindAndReplaceExportTo(WordRTFFindAndReplaceModel model) {
            RichEditFileFormat documentType = model.FileFormat;
            DocumentFormat documentFormat = WordRTFUtils.ConvertToFormat(documentType);
            Stream stream = ExecuteFindAndReplace(documentFormat, model.Find, model.Replace, model.ActionToExec);
            if(stream == null)
                return new EmptyResult();
            string contentType = WordRTFUtils.ConvertToContentType(documentType);
            string fileExtension = WordRTFUtils.ConvertToFileExtension(documentType);
            return CreateFileStreamResult(stream, contentType, fileExtension);
        }

        Stream ExecuteFindAndReplace(DocumentFormat documentFormat, string find, string replace, string action) {
            RichEditDocumentServer documentServer = new RichEditDocumentServer();
            string filePath = HostingEnvironment.ContentRootPath + findAndReplaceFilePath;
            documentServer.LoadDocument(filePath);
            documentServer.Options.Export.Html.EmbedImages = true;
            switch(action) {
                case "replace":
                    ReplaceAll(documentServer, find, replace);
                    break;
                case "find":
                    FindAll(documentServer, find);
                    break;
            }
            MemoryStream result = new MemoryStream();
            if(documentFormat == DocumentFormat.Undefined)
                documentServer.ExportToPdf(result);
            else
                documentServer.SaveDocument(result, documentFormat);
            result.Seek(0, SeekOrigin.Begin);
            return result;
        }

        void ReplaceAll(RichEditDocumentServer documentServer, string strFind, string strReplace) {
            if(!String.IsNullOrEmpty(strFind)) {
                DocumentRange[] ranges = documentServer.Document.FindAll(strFind, SearchOptions.None, documentServer.Document.Range);
                for(int i = 0; i < ranges.Length; i++) {
                    if(strReplace == "null")
                        strReplace = String.Empty;
                    documentServer.Document.Replace(ranges[i], strReplace);
                    CharacterProperties cp = documentServer.Document.BeginUpdateCharacters(ranges[i]);
                    cp.BackColor = System.Drawing.Color.FromArgb(180, 201, 233);
                    documentServer.Document.EndUpdateCharacters(cp);
                };
            }
        }

        void FindAll(RichEditDocumentServer documentServer, string strFind) {
            if(!String.IsNullOrEmpty(strFind)) {
                DocumentRange[] ranges = documentServer.Document.FindAll(strFind, SearchOptions.None, documentServer.Document.Range);
                for(int i = 0; i < ranges.Length; i++) {
                    CharacterProperties cp = documentServer.Document.BeginUpdateCharacters(ranges[i]);
                    cp.BackColor = System.Drawing.Color.FromArgb(180, 201, 233);
                    documentServer.Document.EndUpdateCharacters(cp);
                };
            }
        }
    }
}
namespace AspNetCoreDemos.OfficeFileAPI {
    public class WordRTFFindAndReplaceModel : WordRTFModelBase {

        public WordRTFFindAndReplaceModel() {
            PreviewModel.PreviewDocumentAction = "WordRTFPreviewFindAndReplace";
        }

        public string Find { get; set; }
        public string Replace { get; set; }
        public string ActionToExec { get; set; }
    }
}
namespace AspNetCoreDemos.OfficeFileAPI {
    public class WordRTFModelBase {
        public WordRTFModelBase() {
            PreviewModel = new WordRTFPreviewModel();
            PreviewModel.OwnerPropertyName = "PreviewModel";
            FileFormat = RichEditFileFormat.Rtf;
        }

        public RichEditFileFormat FileFormat { get; set; }
        public WordRTFPreviewModel PreviewModel { get; internal set; }
    }

    public class WordRTFPreviewModel {
        public WordRTFPreviewModel() {
        }

        public string OwnerPropertyName { get; set; }
        public string PreviewDocumentAction { get; set; }
        public string ControllerName { get; set; }
        public int IFrameSize { get; set; } = 452;
    }
}