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
File Format
@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;

namespace AspNetCoreDemos.OfficeFileAPI {
    public partial class ContentManipulationController : DocumentProcessingController {
        public ContentManipulationController(IWebHostEnvironment hostingEnvironment) : base(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;
    }
}