Excel Add-in的笔记
- 一.基础的cshtml部分-打开taskpane
-
- 1.如果你想要tab栏的某个button点击的时候出现的内容显示在taskPane上,那么你可以在对应的cshtml模板文件里加:
- 2.然后在下面resources标签内要加上:(id一定要对上)
- 3. 然后去到program.cs里面,添加Route,pattern要和上边的对应上
- 4. 再去到ExcelAddinController.cs文件里面,加上对应的方法,传进去的"CreateTemplate"就相当于pageName,要对应好要展示的是哪个taskPane
- 5. 因为要显示在task-pane上,所以就要去task-pane组件里面加上,记得一定要写上page-name是“CreateTemplate”,因为这个页面有很多别的页面出现的情况,所以要区分好
- 二.Excel addin(基础的cshtml部分-打开dialog)
- 三.父子组件传参详解(getData,commit,close)
- 四.给excel填充数据001变成了1
- 五.ribbon动态显示(enabled和disabled)
- 六.增删改sheet时数据表格的更新
一.基础的cshtml部分-打开taskpane
存放xml的共享目录地址:\shunified\UnifiedShare\Excel Addin\xml
如果你需要一个新的模板,那就要去Views/ExcelAddin文件夹下创建一个模板,同时记住 < Control> 里面的id是不能一样的,否则这个模板就会无效
1.如果你想要tab栏的某个button点击的时候出现的内容显示在taskPane上,那么你可以在对应的cshtml模板文件里加:
<Action xsi:type="ShowTaskpane">
<TaskpaneId>Aus.HomeTaskPane</TaskpaneId>
<SourceLocation resid="Aus.AddinCreateTemplate.Url" />
</Action>
2.然后在下面resources标签内要加上:(id一定要对上)
<bt:Url id="Aus.AddinCreateTemplate.Url"DefaultValue="@ViewBag.AddinUri/AddinCreateTemplate.html" />
3. 然后去到program.cs里面,添加Route,pattern要和上边的对应上
app.MapControllerRoute(
name: "ExcelAddin/AddinCreateTemplate",
pattern: "ExcelAddin/AddinCreateTemplate.html",
defaults: new { controller = "ExcelAddin", action = "AddinCreateTemplate" }
);
4. 再去到ExcelAddinController.cs文件里面,加上对应的方法,传进去的"CreateTemplate"就相当于pageName,要对应好要展示的是哪个taskPane
public ActionResult AddinCreateTemplate()
{
return AddinAUSTaskPane("CreateTemplate");
}
5. 因为要显示在task-pane上,所以就要去task-pane组件里面加上,记得一定要写上page-name是“CreateTemplate”,因为这个页面有很多别的页面出现的情况,所以要区分好
<create-template if.bind="pageName =='CreateTemplate'" page-name.bind="pageName" is-task-pane="true"></create-template>
二.Excel addin(基础的cshtml部分-打开dialog)
在xml里定义函数名,让他打开指定的dialog(涉及传递数据)
1.在cshtml文件里改一下
<Action xsi:type="ExecuteFunction">
<FunctionName>validateSheets</FunctionName>
</Action>
2.在对应的addin-function-aus.ts页面把相应的方法对应起来
2.1 actions.associate 方法用于将自定义事件与一个处理函数关联起来
actions.associate(CustomEventName.ValidateSheets, this.validateSheets.bind(this));
2.2 处理函数
注意事项:
.给要打开的页面指定好pageName:IpageType.WarningAndError
加自己的组件 warning-error-message
去到dialog-page.html页面把自己的组件加上去
<warning-error-message if.bind="pageName =='WarningAndError'" page-name.bind="pageName" is-task-pane="false"></warning-error-message>
这样dialog里面显示的内容就是我们组件写的内容了
Office.context.ui.displayDialogAsync('https://www.contoso.com/myDialog.html');
- 如果要在函数里面传递数据到组件里面,我们可以使用excel addin里面的API
传递思路:
子页面加载好之后,传递信息----->父页面
父页面接收到消息之后,传递信息---->子页面
子页面接收到信息,使用数据
dialog.messageChild(data) 把主页面信息传递到表格里
DialogParentMessageReceived,可以在receivedMessage 里面得到传递过来的数据
messageParent() 把信息从dialog传递到主页面
dialog.addEventHandler(Office.EventType.DialogMessageReceived, processMessage); 主页面接收dialog传递来的信息
Office.context.ui.addHandlerAsync(
Office.EventType.DialogParentMessageReceived,
this.receivedMessage.bind(this)
)
private validateSheets(event: Office.AddinCommands.Event) {
this.writeToDoc("Ribbon button 'Validate' Clicked");
let noErrorAndMessage = false;
if (noErrorAndMessage) {
this.showMessageInDialog("dialogPage.noErrorAndMessageGuide")
} else {
let allLogs = [
{ "errorType": "warning", "message": "lallala" },
{ "errorType": "warning", "message": "xoxoxox" }
];
const startAdress = this.getUrl("AddinDialog") + "?pageName=" + IpageType.WarningAndError;
const dialogOptions: Office.DialogOptions = {
width: 50,
height: 50,
displayInIframe: Office.context.platform == Office.PlatformType.OfficeOnline,
asyncContext: allLogs
};
Office.context.ui.displayDialogAsync(startAdress, dialogOptions, (r: Office.AsyncResult<Office.Dialog>) => {
// Send allLogs to the dialog when it's loaded
let allLogs = [
{ "errorType": "warning", "message": "lallala" },
{ "errorType": "warning", "message": "xoxoxox" }
];
let dialogMessage = {
type: DialogMessageType.ValidateSheets,
body: {
allLogs: allLogs,
}
};
if (r.status == Office.AsyncResultStatus.Failed) {
this.writeToDoc(r.error.message);
}
if (r.status === Office.AsyncResultStatus.Succeeded) {
let dialog = r.value;
dialog.addEventHandler(Office.EventType.DialogMessageReceived, msg => {
this.writeToDoc(JSON.stringify(msg));
dialog.messageChild(JSON.stringify(dialogMessage));
this.writeToDoc(JSON.stringify(dialogMessage));
})
}
});
}
event.completed();
}
三.父子组件传参详解(getData,commit,close)
父组件向子组件传递数据: 传递思路: 子页面加载好之后,传递信息----->父页面 父页面接收到消息之后,传递信息---->子页面
子页面接收到信息,使用数据
具体详情:我要在点击validate的时候,把读出来的一些warning/error展示在一个dialog里面,我需要把result传到dialog,
createReceivedMessageHandler方法里写的就是具体接收信息做的事情,但是他只是一个中间商,我需要把eventData传递过去,就必须这么写
receivedMessage其实是真正处理接收信息的函数方法
if (r.status === Office.AsyncResultStatus.Succeeded) {
this.dialog = r.value;
this.dialog.addEventHandler(Office.EventType.DialogMessageReceived, this.createReceivedMessageHandler(true, eventData));
this.highlightCells(this.auditResult);
}
private createReceivedMessageHandler(showCommitButtonValue,eventData) {
return (args) => {
this.receivedMessage(this.dialog, args, showCommitButtonValue,eventData);
};
}
auditResult就是要传递给子组件的数据,需要先得到子组件发给父组件的信息我们再传过去
commit是子组件传过来的(证明用户点击了commit button),然后我们直接调用更新的graphql语句
private async receivedMessage(dialog: Office.Dialog, args: { message: string }, showCommitButton?: boolean,eventData?) {
let dialogMsg: IDialogMessage = JSON.parse(args.message);
this.writeToDoc("receivedMessage from child: " + args.message);
if (dialogMsg.type == DialogMessageType.RequestValidateSheetsInfo) {
let dialogMessage = {
type: DialogMessageType.ValidateSheets,
body: {
auditResult: this.auditResult,
showCommitButton: showCommitButton,
eventData: eventData
}
};
dialog.messageChild(JSON.stringify(dialogMessage));
} else if (dialogMsg.type == DialogMessageType.Commit) {
await this.schedulingAgent.addAndUpdateReceiptEvents(eventData);
dialog.close();
this.writeToDoc("commit successfully");
} else if (dialogMsg.type == DialogMessageType.Close) {
dialog.close();
} else if (dialogMsg.type == DialogMessageType.CreateEnd) {
dialog.close();
this.writeToDoc("add case successfully");
}
}
四.给excel填充数据001变成了1
使用 numberFormat 属性将单元格格式设置为文本。‘@’ 是 Excel 中表示文本格式的符号。
五.ribbon动态显示(enabled和disabled)
需要根据逻辑判断来决定是否enabled或者disabled,一定要把id对应好
发送信息:
parent.postMessage({ action: "updateRibbonState", selectedData: workspace.connected }, "*");
接收信息并更新ribbon:
window.addEventListener("message", (event) => {
if (event.data.action == "updateRibbonState") {
let buttonEnabled = event.data && event.data.selectedData;
updateRibbonButtons(buttonEnabled);
}
});
一定要注意,如果有共享的内容需要在taskpane显示,这个taskpane的id一定要是唯一的!!!不能和别的共享,否则会出现不能正常加载的问题
• Office 客户端会根据 TaskpaneId 判断是否已存在同 ID 的任务窗格。若存在,则会尝试复用(如刷新内容),而非重复创建新实例
例如:若两个按钮共享同一个 TaskpaneId,点击第二个按钮时会直接激活已存在的窗格,而非打开新页面。
六.增删改sheet时数据表格的更新
- 事件监听器注册:
• 在 attached 方法中调用 registerWorksheetAddedListener 方法注册工作表添加事件监听器。
• 使用 this.handleWorksheetAdded.bind(this) 确保事件处理函数中的 this 指向正确的上下文。 - 事件处理函数:
• 在 handleWorksheetAdded 方法中,使用 await context.sync() 确保在获取工作表名称后,再更新 mappingData。
• 更新 mappingData 后,调用 saveToCache 方法保存数据。
• 调用 this.gridOptions.api.setRowData(this.mappingData) 更新网格数据。 - 确保网格更新:
• 在事件处理函数中,确保 this.gridOptions.api 存在,再调用 setRowData 方法
private registerWorksheetAddedListener() {
Excel.run(async (context) => {
const worksheetCollection = context.workbook.worksheets;
worksheetCollection.onAdded.add(this.handleWorksheetAdded.bind(this));
await context.sync();
console.log("Event handler successfully registered for onAdded event in the worksheet collection.");
});
}
private async handleWorksheetAdded(event: Excel.WorksheetAddedEventArgs) {
await Excel.run(async (context) => {
const worksheet = context.workbook.worksheets.getItem(event.worksheetId);
worksheet.load("name");
await context.sync();
this.mappingData.push({
sheetName: worksheet.name,
templateName: "",
active: false,
});
this.saveToCache(this.mappingData);
if (this.gridOptions && this.gridOptions.api) {
this.gridOptions.api.setRowData(this.mappingData);
this.onGridResize();
}
console.log("A new worksheet has been added: " + worksheet.name);
});
}