Add custom UI to a spreadsheet document
Custom UI is stored in package parts related from the spreadsheet document package. It is not part of worksheet cell data.
The upstream sample customizes the Excel ribbon. The custom UI XML describes a button on the Add-ins tab and points that button at a macro in the host workbook. For that scenario, the workbook is normally macro-enabled (.xlsm) and already contains the macro that the ribbon callback names.
Package model
Custom UI parts commonly use Office relationship types for ribbon extensibility or user customization. A valid update needs:
- the custom UI XML part,
- the package relationship to that part,
- content type metadata,
- any images or resources referenced by the custom UI.
The ribbon extensibility part is a package-level part. If it does not exist, a writer must create it; if it already exists, a writer should update only the intended custom UI payload and preserve unrelated package relationships.
Rust workflow
Use SpreadsheetDocument to open and save the package. The package-side custom UI operation is now covered by a tested listing: add a ribbon extensibility part at the package level, write the custom UI XML, and save.
#![allow(unused)] fn main() { pub fn add_custom_ui_part( path: &Path, relationship_id: &str, custom_ui_xml: &[u8], ) -> Result<(Vec<u8>, String), Box<dyn std::error::Error>> { let mut document = SpreadsheetDocument::new_from_file_with_settings(path, lazy_settings())?; let custom_ui_part = document.add_new_part::<RibbonExtensibilityPart>(relationship_id)?; custom_ui_part.set_data(&mut document, custom_ui_xml.to_vec())?; let mut buffer = Cursor::new(Vec::new()); document.save(&mut buffer)?; Ok((buffer.into_inner(), relationship_id.to_string())) } }
This covers the package relationship and part payload. A complete macro-enabled ribbon scenario still needs the workbook to contain the callback macro named by the custom UI XML, and any referenced custom UI images must be added as related parts.