开发Excel Add-in的心得笔记

发布于:2025-08-15 ⋅ 阅读:(12) ⋅ 点赞:(0)

一.基础的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时数据表格的更新

  1. 事件监听器注册:
    • 在 attached 方法中调用 registerWorksheetAddedListener 方法注册工作表添加事件监听器。
    • 使用 this.handleWorksheetAdded.bind(this) 确保事件处理函数中的 this 指向正确的上下文。
  2. 事件处理函数:
    • 在 handleWorksheetAdded 方法中,使用 await context.sync() 确保在获取工作表名称后,再更新 mappingData。
    • 更新 mappingData 后,调用 saveToCache 方法保存数据。
    • 调用 this.gridOptions.api.setRowData(this.mappingData) 更新网格数据。
  3. 确保网格更新:
    • 在事件处理函数中,确保 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);
        });
    }


网站公告

今日签到

点亮在社区的每一天
去签到