如何在不同的 Word.run 上下文中使用范围?
How can a range be used across different Word.run contexts?
我为单词创建了一个任务面板插件,运行它是一个搜索并以列表的形式向用户显示有关结果的信息。
当用户单击列表中的项目时,我想 select word 中的范围向用户显示项目的位置。
然后插件将允许用户在范围内执行其他任务,例如更改字体颜色。
我可以使用以下函数运行搜索并获取显示范围:
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;
});
};
但是我在 select 用户点击范围时遇到困难。
我尝试使用范围上下文:
function selectRange(range){
range.select();
return range.context.sync();
}
或在新的 Word.run 上下文中使用范围:
function selectRange(range){
return Word.run(function(context) {
context.load(range);
return context.sync().then(function(){
range.select();
return context.sync();
});
});
}
我遇到了一种可能的方法,它涉及为每个搜索结果创建一个内容控件,然后在新上下文中的 selectRange
函数中重新加载所有内容控件并找到匹配的控件,但这似乎当我已经有了范围时效率很低。
在不同 Word.run 上下文中重复使用范围的最佳方法是什么?
您不能在 Word.run
次调用中使用一个对象。 Word.run
每次调用时都会创建一个新的上下文,而原始对象绑定到它自己的上下文,从而造成不匹配。
话虽如此,您绝对可以,从 Word.run
中,将您想要的对象添加到 context.trackedObjects.add(obj)
,它们将保持正常工作即使在 Word.run 完成执行后的对象。 "working objects" 我的意思是他们的路径不会失效(想想类似于垃圾收集的东西,但对于远程对象)。
一旦你有了这样的对象(上面看起来像你做的),你应该可以调用
range.select();
range.context.sync().catch(...);
如果它不适合你,你能提供一个你遇到的错误的例子吗?
为了完整起见,我应该指出,一旦您将对象添加到 trackedObjects 集合,您实际上就在自己手中管理这些对象的内存。这意味着,如果您没有正确释放内存,您 将 使内存/范围调整链陷入困境,从而减慢 Word 的运行速度。因此,一旦您使用完被跟踪对象,您应该调用 obj.context.trackedObjects.remove(obj)
,然后调用 obj.context.sync()
。不要忘记最后一部分 - 如果您不进行同步,您删除跟踪对象的请求将不会被调度,并且您将继续耗尽内存。
======= 更新 1 =======
汤姆,感谢您提供错误信息。看起来这可能是 API 的 Word 实现中的错误——我会跟进,如果有更多问题,可能会有人与您联系。
从概念的角度来看,您绝对是在正确的道路上——下面的内容在 Excel 中确实有效,例如:
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 =======
原来产品确实有bug。然而,好消息是使用 JavaScript-only 修复很容易修复,事实上我们将在接下来的几周内这样做,更新 CDN。
修复后,以下代码有效:
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 更新之前,您可以使用下面的代码 "patch" JavaScript 库并制作上面的代码 运行。在 Office.js 已经加载之后(即,在您的 Office.initialize 函数中)和执行 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 可扩展性团队开发人员
除了 TrackedObjects 修复需要更新 runSearch 方法以获取 searchResult 的范围,而不是直接使用 searchResult。
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);
return context.sync().then(function() {
for (var i = 0; i < rangesFind.items.length; i++) {
var range = rangesFind.items[i].getRange();
context.load(range, 'text');
items.push(range);
context.trackedObjects.add(items[items.length-1]);
}
return context.sync();
});
})
.then(function() {
return items;
});
};
我为单词创建了一个任务面板插件,运行它是一个搜索并以列表的形式向用户显示有关结果的信息。 当用户单击列表中的项目时,我想 select word 中的范围向用户显示项目的位置。 然后插件将允许用户在范围内执行其他任务,例如更改字体颜色。
我可以使用以下函数运行搜索并获取显示范围:
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;
});
};
但是我在 select 用户点击范围时遇到困难。 我尝试使用范围上下文:
function selectRange(range){
range.select();
return range.context.sync();
}
或在新的 Word.run 上下文中使用范围:
function selectRange(range){
return Word.run(function(context) {
context.load(range);
return context.sync().then(function(){
range.select();
return context.sync();
});
});
}
我遇到了一种可能的方法,它涉及为每个搜索结果创建一个内容控件,然后在新上下文中的 selectRange
函数中重新加载所有内容控件并找到匹配的控件,但这似乎当我已经有了范围时效率很低。
在不同 Word.run 上下文中重复使用范围的最佳方法是什么?
您不能在 Word.run
次调用中使用一个对象。 Word.run
每次调用时都会创建一个新的上下文,而原始对象绑定到它自己的上下文,从而造成不匹配。
话虽如此,您绝对可以,从 Word.run
中,将您想要的对象添加到 context.trackedObjects.add(obj)
,它们将保持正常工作即使在 Word.run 完成执行后的对象。 "working objects" 我的意思是他们的路径不会失效(想想类似于垃圾收集的东西,但对于远程对象)。
一旦你有了这样的对象(上面看起来像你做的),你应该可以调用
range.select();
range.context.sync().catch(...);
如果它不适合你,你能提供一个你遇到的错误的例子吗?
为了完整起见,我应该指出,一旦您将对象添加到 trackedObjects 集合,您实际上就在自己手中管理这些对象的内存。这意味着,如果您没有正确释放内存,您 将 使内存/范围调整链陷入困境,从而减慢 Word 的运行速度。因此,一旦您使用完被跟踪对象,您应该调用 obj.context.trackedObjects.remove(obj)
,然后调用 obj.context.sync()
。不要忘记最后一部分 - 如果您不进行同步,您删除跟踪对象的请求将不会被调度,并且您将继续耗尽内存。
======= 更新 1 =======
汤姆,感谢您提供错误信息。看起来这可能是 API 的 Word 实现中的错误——我会跟进,如果有更多问题,可能会有人与您联系。
从概念的角度来看,您绝对是在正确的道路上——下面的内容在 Excel 中确实有效,例如:
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 =======
原来产品确实有bug。然而,好消息是使用 JavaScript-only 修复很容易修复,事实上我们将在接下来的几周内这样做,更新 CDN。
修复后,以下代码有效:
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 更新之前,您可以使用下面的代码 "patch" JavaScript 库并制作上面的代码 运行。在 Office.js 已经加载之后(即,在您的 Office.initialize 函数中)和执行 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 可扩展性团队开发人员
除了 TrackedObjects 修复需要更新 runSearch 方法以获取 searchResult 的范围,而不是直接使用 searchResult。
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);
return context.sync().then(function() {
for (var i = 0; i < rangesFind.items.length; i++) {
var range = rangesFind.items[i].getRange();
context.load(range, 'text');
items.push(range);
context.trackedObjects.add(items[items.length-1]);
}
return context.sync();
});
})
.then(function() {
return items;
});
};