如何在不同的 Word.run 上下文中使用范围? [英] How can a range be used across different Word.run contexts?

查看:13
本文介绍了如何在不同的 Word.run 上下文中使用范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为 word 创建了一个任务面板插件,它运行搜索并将结果信息作为列表显示给用户.当用户单击列表中的项目时,我想选择 word 中的范围以向用户显示该项目的位置.然后,插件将允许用户对范围执行其他任务,例如更改字体颜色.

I have created a taskpane addin for word that runs a search and displays information about the results as a list to the user. When the user clicks on an item in the list I want to select the range in word to show the user the location of the item. The addin will then allow the user to perform additional tasks on the range, for example change the font colour.

我可以使用以下函数运行搜索并获取显示范围:

I am able to run the search and get ranges for display using the function below:

function runSearch(textToFind) {
  var items = [];
  return Word.run(function(context) {
    var options = Word.SearchOptions.newObject(context);
    options.matchWildCards = false;

    var rangesFind = context.document.body.search(textToFind, options);
    context.load(rangesFind, 'text, font, style');
    return context.sync().then(function() {
      for (var i = 0; i < rangesFind.items.length; i++) {
        items.push(rangesFind.items[i]);
        context.trackedObjects.add(rangesFind.items[i]);
      }
      return context.sync();
    });
  })
  .then(function() {
    return items;
  });
}; 

但是我在用户点击时选择范围有困难.我曾尝试使用范围上下文:

However I am having difficulty selecting the range on user click. I have tried using the ranges context:

function selectRange(range){
  range.select();
  return range.context.sync();
}

或者在新的 Word.run 上下文中使用范围:

Or using the range in a new Word.run context:

function selectRange(range){
  return Word.run(function(context) {
    context.load(range);
    return context.sync().then(function(){
      range.select();
      return context.sync();
    });
  });
}

我遇到了一种潜在的方法,该方法涉及为每个搜索结果创建一个内容控件,然后在新上下文中重新加载 selectRange 函数中的所有内容控件并找到匹配的控件,但是当我已经有了范围时,似乎效率很低.

I have come across a potential method that involves creating a content control for each search result and then reloading all the content controls in the selectRangefunction in the new context and finding the matching control, but that seems very inefficient when I have the range already.

在不同的 Word.run 上下文中重用范围的最佳方法是什么?

What is the best method for reusing a range across different Word.run contexts?

推荐答案

不能跨 Word.run 调用使用对象.Word.run 每次被调用时都会创建一个新的上下文,而原始对象与其自己的上下文相关联,从而造成不匹配.

You cannot use an object across Word.run invocations. Word.run creates a new context every time that it's invoked, whereas the original object is tied to its own context, creating a mismatch.

话虽如此,您绝对可以,从Word.run 中,将您想要的对象添加到context.trackedObjects.add(obj),即使在 Word.run 完成执行后,它们仍将保留为工作对象.工作对象"是指它们的路径不会失效(想想类似于垃圾收集的东西,但对于远程对象).

That being said, you absolutely can, from within a Word.run, add the objects you desire to context.trackedObjects.add(obj), and they will remain as working objects even after Word.run finishes executing. By "working objects" I mean that their path will not get invalidated (think something similar to garbage collection, but for remote objects).

一旦你有了这样的对象(它看起来像你做的那样),你应该可以调用

Once you have such object (and it looks above like you do), you should be able to call

range.select();
range.context.sync().catch(...);

如果它不适合你,你能提供一个你遇到的错误的例子吗?

If it's not working for you, can you provide an example of the error you're getting?

为了完整起见,我应该指出,一旦您将对象添加到 trackedObjects 集合,您就可以有效地将这些对象的内存管理掌握在自己手中.这意味着如果您没有正确释放内存,您拖住 Word 的内存/范围调整链,从而减慢 Word 的速度.所以一旦你使用完被跟踪的对象,你应该调用 obj.context.trackedObjects.remove(obj),然后是 obj.context.sync().不要忘记最后一部分——如果你不做同步,你移除被跟踪对象的请求将不会被分派,你将继续使用内存.

For completeness sake, I should note that once you add objects to the trackedObjects collection, you're effectively taking memory management of those objects into your own hands. This means that if you don't properly release the memory, you will be slowing down Word by bogging down its memory / range-adjustment chain. So once you're done using the tracked object(s), you should call obj.context.trackedObjects.remove(obj), followed by obj.context.sync(). Don't forget the last part - if you don't do a sync, your request to remove the tracked objects will not be dispatched, and you'll continue to use up the memory.

======= 更新 1 ========

Tom,感谢您提供错误消息.看起来这可能是 API 的 Word 实现中的一个错误 - 我会跟进此事,如果有更多问题,有人可能会与您联系.

Tom, thanks for providing the error message. It looks like this might be a bug in the Word implementation of the APIs -- I'll follow up on that, and someone might reach out to you if there's more questions.

从概念的角度来看,您绝对走在正确的道路上——例如,以下内容在 Excel 中确实有效:

From a conceptual standpoint, you are absolutely on the right path -- and the following does work in Excel, for example:

var range;
Excel.run(function (ctx) {
    var sheet = ctx.workbook.worksheets.getActiveWorksheet();

    range = sheet.getRange("A5");
    range.values = [[5]];
    ctx.trackedObjects.add(range);

    return ctx.sync();
})
.then(function(){
    setTimeout(function() {
        range.select();
        range.context.trackedObjects.remove(range);
        range.context.sync();
    }, 2000);
})
.catch(function (error) {
    showMessage("Error: " + error);        
});

======= 更新 2 ========

事实证明该产品确实存在错误.不过,好消息是,通过仅使用 JavaScript 的修复程序很容易修复,事实上,我们将在接下来的几周内更新 CDN.

It turns out there is indeed a bug in the product. However, the good news is that it's easy to fix with a JavaScript-only fix, and in fact we'll do so in the next couple of weeks, updating the CDN.

修复后,以下代码有效:

With the fix, the following code works:

var paragraph;
Word.run(function (ctx) {
    var p = ctx.document.body.paragraphs.first;
    paragraph = p.next;
    ctx.trackedObjects.add(paragraph);
    return ctx.sync();
})
.then(function(){
    setTimeout(function() {
        paragraph.select();
        paragraph.context.trackedObjects.remove(paragraph);
        paragraph.context.sync()
            .then(function() {
                console.log("Done");
            })
            .catch(handleError);
    }, 2000);
})
.catch(handleError);

function handleError (error) {
    console.log('Error: ' + JSON.stringify(error));
    if (error instanceof OfficeExtension.Error) {
        console.log('Debug info: ' + JSON.stringify(error.debugInfo));
    }
}

想要更好的消息吗?在 CDN 更新之前,您可以使用下面的代码修补"JavaScript 库并使上面的代码运行.你应该在 Office.js 已经加载之后(即在你的 Office.initialize 函数中)运行这段代码,然后在你执行 Word.run 之前.

Want even better news? Until the CDN is updated, you can use the code below to "patch" the JavaScript library and make the code above run. You should run this code some time after Office.js has already loaded (i.e., within your Office.initialize function), and before you do a Word.run.

var TrackedObjects = (function () {
    function TrackedObjects(context) {
        this._autoCleanupList = {};
        this.m_context = context;
    }
    TrackedObjects.prototype.add = function (param) {
        var _this = this;
        if (Array.isArray(param)) {
            param.forEach(function (item) { return _this._addCommon(item, true); });
        }
        else {
            this._addCommon(param, true);
        }
    };
    TrackedObjects.prototype._autoAdd = function (object) {
        this._addCommon(object, false);
        this._autoCleanupList[object._objectPath.objectPathInfo.Id] = object;
    };
    TrackedObjects.prototype._addCommon = function (object, isExplicitlyAdded) {
        if (object[OfficeExtension.Constants.isTracked]) {
            if (isExplicitlyAdded && this.m_context._autoCleanup) {
                delete this._autoCleanupList[object._objectPath.objectPathInfo.Id];
            }
            return;
        }
        var referenceId = object[OfficeExtension.Constants.referenceId];
        if (OfficeExtension.Utility.isNullOrEmptyString(referenceId) && object._KeepReference) {
            object._KeepReference();
            OfficeExtension.ActionFactory.createInstantiateAction(this.m_context, object);
            if (isExplicitlyAdded && this.m_context._autoCleanup) {
                delete this._autoCleanupList[object._objectPath.objectPathInfo.Id];
            }
            object[OfficeExtension.Constants.isTracked] = true;
        }
    };
    TrackedObjects.prototype.remove = function (param) {
        var _this = this;
        if (Array.isArray(param)) {
            param.forEach(function (item) { return _this._removeCommon(item); });
        }
        else {
            this._removeCommon(param);
        }
    };
    TrackedObjects.prototype._removeCommon = function (object) {
        var referenceId = object[OfficeExtension.Constants.referenceId];
        if (!OfficeExtension.Utility.isNullOrEmptyString(referenceId)) {
            var rootObject = this.m_context._rootObject;
            if (rootObject._RemoveReference) {
                rootObject._RemoveReference(referenceId);
            }
            delete object[OfficeExtension.Constants.isTracked];
        }
    };
    TrackedObjects.prototype._retrieveAndClearAutoCleanupList = function () {
        var list = this._autoCleanupList;
        this._autoCleanupList = {};
        return list;
    };
    return TrackedObjects;
}());
OfficeExtension.TrackedObjects = TrackedObjects;

希望这有帮助!

~ Michael Zlatkovsky,MSFT Office 可扩展性团队的开发人员

~ Michael Zlatkovsky, developer on Office Extensibility team, MSFT

这篇关于如何在不同的 Word.run 上下文中使用范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆