#office-js #custom-functions-excel
Вопрос:
В настоящее время я работаю над переходом от пользовательской функции.Вызов к потоковому вызову в проекте надстройки общей среды выполнения, потому что мне придется использовать веб-сокет. У меня есть вариант использования, в котором необходимо использовать свойство адреса пользовательской функции в качестве ключа в объекте данных для дальнейшего использования, и я обнаружил, что его нельзя использовать с потоковым вызовом. Я попытался реализовать обходной путь с OnChanged и onCalculated событием, но это работало не очень хорошо. Поэтому я не уверен, что есть какие-то обходные пути, которые я могу использовать, чтобы получить свойство адреса пользовательской функции внутри самой себя.
Изменить: Добавить код и более подробную информацию
export class TestExcelService {
private static instance: TestExcelService;
private dataEventEmtter?: EventEmitter;
// prevent direct construction call with new keyword.
// eslint-disable-next-line @typescript-eslint/no-empty-function
private constructor() {
this.registerOnCalculated();
}
public static getInstance(): TestExcelService {
if (!TestExcelService.instance) {
TestExcelService.instance = new TestExcelService();
}
return TestExcelService.instance;
}
public setDataEventEmtter(eventEmitter: EventEmitter): void {
this.dataEventEmtter = eventEmitter;
}
public getDataEventEmtter(): EventEmitter | undefined {
return this.dataEventEmtter;
}
private async registerOnCalculated(): Promise<void> {
await Excel.run(async (context: Excel.RequestContext) => {
context.workbook.worksheets.getActiveWorksheet().onCalculated.add(
async (arg: Excel.WorksheetCalculatedEventArgs): Promise<void> => {
const formulaAddresses: ICellAddress[] = await this.filterMyFormulaAddress(arg);
if (this.dataEventEmtter amp;amp; formulaAddresses.length > 0) {
this.dataEventEmtter.emit('onExcelCalculated', formulaAddresses);
}
},
);
});
}
private async filterMyFormulaAddress(arg: Excel.WorksheetCalculatedEventArgs): Promise<ICellAddress[]> {
// filter only some formulas
return [];
}
}
export class TestDataService {
private eventEmitter: EventEmitter = new EventEmitter();
private static instance: TestDataService;
private dataQueue = [];
// prevent direct construction call with new keyword.
// eslint-disable-next-line @typescript-eslint/no-empty-function
private constructor() {
this.eventEmitter.addListener('onExcelCalculated', this.excelCalculatedHandler.bind(this));
}
public static getInstance(): TestDataService {
if (!TestDataService.instance) {
TestDataService.instance = new TestDataService();
}
return TestDataService.instance;
}
public addDataToQueue(data): void {
const duplicatedIndex: number = this.dataQueue.findIndex(
(queueData) => data.formulaId === queueData.formulaId,
);
if (duplicatedIndex < 0) {
this.dataQueue.push(data);
}
}
public getEventEmitter(): EventEmitter {
return this.eventEmitter;
}
private async excelCalculatedHandler(formulaAddresses: ICellAddress[]): Promise<void> {
if (Array.isArray(this.dataQueue) amp;amp; this.dataQueue.length > 0) {
// check that data queue is not empty and map formula addresses from onCalculated event to the data queue
}
}
}
Я не могу опубликовать полный код, поэтому мне придется удалить и изменить некоторые части кода.
Общая идея заключается в том, что я добавлю объекты данных, которые должны быть сопоставлены с их соответствующим адресом формулы, в очередь данных в DataService, и после запуска события onCalculated я смогу получить список вычисленных и отфильтрованных адресов.
Из того, что я проверил, порядок адресов формул должен совпадать с порядком очереди данных. Сначала кажется, что этот обходной путь работает нормально, когда я выполняю по одной формуле за раз или пересчитываю небольшое количество формул одновременно, но когда количество формул начинает расти, и я пытаюсь пересчитать все формулы, порядок адресов формул и очередь данных не будут совпадать, как я ожидал.
Комментарии:
1. Не могли бы вы добавить код, который вы использовали?
2. Привет @MaartenDev, я добавил код в сообщение, а также некоторые дополнительные детали.
Ответ №1:
Функция потоковой передачи является специальной. Если какой-либо набор потоковых функций использует одно и то же выражение, они используют один и тот же корень (т. Е. контекст). Область действия будет хорошей в пределах рабочей книги. В другой рабочей книге контекст будет другим. Таким образом, для функции потоковой передачи не предоставляется адресная информация. Как вы заметили, событие onCalculated будет регистрировать все вычисленные адреса. Однако для особых запросов на адреса требуется дополнительная логика, например, сохранение порядка адресов формул в соответствии с очередью данных в вашем случае.