Files
Common-VS2019/SacsStandardProc/Proc/Excel/SaMsSpreadsheet_OpenXml.cs
T
2025-11-20 17:17:40 +00:00

730 lines
23 KiB
C#

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Sarand.Net.Standard.Proc.Excel
{
//=======================================================================
public class SaMsSpreadsheet_OpenXml : SaMsSpreadsheet
{
//-------------------------------------------------------------------
// Data members.
private class WorkbookData
{
public SpreadsheetDocument Document { get; set; }
public MemoryStream MemoryStream { get; set; }
public WorkbookPart WorkbookPart { get { return Document.WorkbookPart; } }
}
private WorkbookData workbook;
private class WorksheetData
{
public WorksheetData(uint worksheetPos, WorksheetPart worksheetPart, Sheet sheet)
{
WorksheetPos = worksheetPos;
WorksheetPart = worksheetPart;
Sheet = sheet;
}
public uint WorksheetPos { get; }
public WorksheetPart WorksheetPart { get; }
public Sheet Sheet { get; }
public SheetData SheetData { get { return WorksheetPart.Worksheet.GetFirstChild<SheetData>(); } }
// Active column.
public uint ActiveColumnPos { get; private set; }
public Column ActiveColumn { get; private set; }
public void SetActiveColumn(uint activeColumnPos, Column activeColumn)
{
ActiveColumnPos = activeColumnPos;
ActiveColumn = activeColumn;
}
public void ClearActiveColumn()
{
ActiveColumnPos = 0;
ActiveColumn = null;
}
// Active row.
public uint ActiveRowPos { get; private set; }
public Row ActiveRow { get; private set; }
public void SetActiveRow(uint activeRowPos, Row activeRow)
{
ActiveRowPos = activeRowPos;
ActiveRow = activeRow;
}
public void ClearActiveRow()
{
ActiveRowPos = 0;
ActiveRow = null;
}
}
private WorksheetData worksheet;
private uint activeWorksheetPos;
//-------------------------------------------------------------------
// Construction.
public SaMsSpreadsheet_OpenXml() : base()
{
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
CloseWorkbook();
}
base.Dispose(disposing);
}
//-------------------------------------------------------------------
// Properties.
private WorkbookPart WorkbookPart { get { return workbook.WorkbookPart; } }
private Sheets Sheets { get { return WorkbookPart.Workbook.Sheets; } }
//-------------------------------------------------------------------
// W o r k b o o k
//-------------------------------------------------------------------
public override bool IsWorkbookValid()
{
return (workbook != null);
}
public override bool CreateWorkbook()
{
ClearErrorState();
CloseWorkbook();
try
{
workbook = new WorkbookData();
workbook.MemoryStream = new MemoryStream();
workbook.Document = SpreadsheetDocument.Create(workbook.MemoryStream, SpreadsheetDocumentType.Workbook);
}
catch (Exception exc) { SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetErrorStateMessage(exc)}"); }
return (workbook != null);
}
public override bool OpenWorkbook(String filePath)
{
ClearErrorState();
CloseWorkbook();
try
{
workbook = new WorkbookData();
workbook.Document = SpreadsheetDocument.Create(filePath, SpreadsheetDocumentType.Workbook);
}
catch (Exception exc) { SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetErrorStateMessage(exc)}"); }
return (workbook != null);
}
public override bool CleanseWorkbook()
{
throw new NotSupportedException(SysUtil.Fn);
}
public override bool SaveDocument(String filePath, int fileFormat, bool bAutomaticallyOverwrite)
{
ClearErrorState();
#pragma warning disable CS0219 // Variable is assigned but its value is never used
SpreadsheetDocumentType documentType = SpreadsheetDocumentType.Workbook;
#pragma warning restore CS0219 // Variable is assigned but its value is never used
if (fileFormat == (int)XlFileFormat.xlOpenXMLTemplate || fileFormat == (int)XlFileFormat.xlTemplate || fileFormat == (int)XlFileFormat.xlTemplate8)
documentType = SpreadsheetDocumentType.Template;
else if (fileFormat == (int)XlFileFormat.xlOpenXMLWorkbookMacroEnabled)
documentType = SpreadsheetDocumentType.MacroEnabledWorkbook;
else if (fileFormat == (int)XlFileFormat.xlOpenXMLTemplateMacroEnabled)
documentType = SpreadsheetDocumentType.MacroEnabledTemplate;
else if (fileFormat == (int)XlFileFormat.xlOpenXMLAddIn || fileFormat == (int)XlFileFormat.xlAddIn || fileFormat == (int)XlFileFormat.xlAddIn8 || fileFormat == (int)XlFileFormat.xlIntlAddIn)
documentType = SpreadsheetDocumentType.AddIn;
// ToDo Save OpenXML Excel document.
return OK;
}
public override bool CloseWorkbook()
{
ClearErrorState();
CloseWorksheet();
try
{
if (workbook != null)
{
if (workbook.Document != null) workbook.Document.Dispose();
if (workbook.MemoryStream != null) workbook.MemoryStream.Dispose();
workbook = null;
}
}
catch (Exception exc) { SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetErrorStateMessage(exc)}"); }
workbook = null;
return OK;
}
/// <summary>Extract the document as a byte array.</summary>
/// <returns>Document data as byte array.</returns>
public override byte[] GetDocumentData()
{
throw new NotSupportedException(SysUtil.Fn);
}
// Default style.
public override void ApplyDefaultStyle(SaMsExcelStyleAttr attr)
{
throw new NotSupportedException(SysUtil.Fn);
}
//-------------------------------------------------------------------
// W o r k s h e e t s
//-------------------------------------------------------------------
public override uint WorksheetCount
{
get
{
uint worksheetCount = 0;
foreach (Sheet sheet in Sheets)
worksheetCount++;
return worksheetCount;
}
}
public override bool SetWorksheetCount(int worksheetCount)
{
ClearErrorState();
if (worksheetCount > 0 && worksheetCount < 11)
{
while (WorksheetCount < worksheetCount)
AddWorksheet("");
while (WorksheetCount > worksheetCount)
RemoveWorksheet(WorksheetCount);
OpenWorksheet(1);
}
else SetErrorState("SetWorksheetCount - Requested number of worksheets (" + worksheetCount.ToString() + ") must be between 1 and 10");
return OK;
}
//-------------------------------------------------------------------
public override List<String> WorksheetNames { get { return new List<String>(); } }
//-------------------------------------------------------------------
public override bool AddWorksheet(String sheetName)
{
ClearErrorState();
CloseWorksheet();
// Add a blank WorksheetPart.
WorksheetPart worksheetPart = WorkbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
// Get a unique ID for the new worksheet.
Sheets sheets = WorkbookPart.Workbook.GetFirstChild<Sheets>();
uint sheetId = 1;
if (sheets.Elements<Sheet>().Count() > 0)
{
sheetId = sheets.Elements<Sheet>().Select(item => item.SheetId.Value).Max() + 1;
}
// Append the new worksheet and associate it with the workbook.
String relationshipId = WorkbookPart.GetIdOfPart(worksheetPart);
sheetName = StringUtil.OnEmpty(StringUtil.TrimAll(sheetName), "Sheet" + sheetId);
Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetName };
sheets.Append(sheet);
worksheet = new WorksheetData(WorksheetCount, worksheetPart, sheet);
return (worksheet != null);
}
//-------------------------------------------------------------------
public override bool RemoveWorksheet(uint worksheetPos)
{
ClearErrorState();
// Extract Sheet by position.
int sheetCount = 0;
Sheet sheet = null;
foreach (Sheet sheetCandidate in Sheets)
{
if (++sheetCount == worksheetPos)
{
sheet = sheetCandidate;
break;
}
}
if (sheet != null)
{
// Extract the corresponding Worksheet Part.
WorksheetPart worksheetPart = (WorksheetPart)(WorkbookPart.GetPartById(sheet.Id));
// Check if the worksheet being removed is currently open.
if (worksheet != null && sheet.Id == worksheet.Sheet.Id)
CloseWorksheet();
// Remove the sheet from the workbook.
sheet.Remove();
WorkbookPart.DeletePart(worksheetPart);
return true;
}
return false;
}
//-------------------------------------------------------------------
// W o r k s h e e t
//-------------------------------------------------------------------
public override bool OpenWorksheet(uint worksheetPos)
{
ClearErrorState();
CloseWorksheet();
// Extract Sheet by position.
int sheetCount = 0;
Sheet sheet = null;
foreach (Sheet sheetCandidate in Sheets)
{
if (++sheetCount == worksheetPos)
{
sheet = sheetCandidate;
break;
}
}
if (sheet != null)
{
WorksheetPart worksheetPart = (WorksheetPart)(WorkbookPart.GetPartById(sheet.Id));
if (worksheetPart != null && sheet != null)
worksheet = new WorksheetData(worksheetPos, worksheetPart, sheet);
}
if (worksheet != null)
{
SaLogger.Warn(SysUtil.Fn + " Failed to open worksheet " + worksheetPos);
SetErrorState("Failed to open worksheet " + worksheetPos);
}
return (worksheet != null);
}
public override bool OpenWorksheet(String name)
{
ClearErrorState();
CloseWorksheet();
name = StringUtil.TrimWhitespace(name);
// Extract Sheet by position.
uint worksheetPos = 0;
Sheet sheet = null;
foreach (Sheet sheetCandidate in Sheets)
{
++worksheetPos;
if (StringUtil.TrimWhitespace(sheetCandidate.Name).EqualsCI(name))
{
sheet = sheetCandidate;
break;
}
}
if (sheet != null)
{
WorksheetPart worksheetPart = (WorksheetPart)(WorkbookPart.GetPartById(sheet.Id));
if (worksheetPart != null && sheet != null)
worksheet = new WorksheetData(worksheetPos, worksheetPart, sheet);
}
if (worksheet != null)
{
String msg = "Failed to open worksheet: " + name;
SetErrorState(msg);
SaLogger.Warn(SysUtil.Fn + " " + msg);
}
return (worksheet != null);
}
//-------------------------------------------------------------------
public override bool CloseWorksheet()
{
ClearErrorState();
try
{
if (worksheet != null)
{
// No worksheet components need to be disposed - they belong to the workbook.
}
worksheet = null;
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
worksheet = null;
activeWorksheetPos = 0;
return OK;
}
//-------------------------------------------------------------------
public override bool IsWorksheetValid()
{
return (worksheet != null);
}
//-------------------------------------------------------------------
public override uint WorksheetPos { get { return activeWorksheetPos; } }
public override String WorksheetName
{
get { return worksheet.Sheet.Name; }
set { worksheet.Sheet.Name = StringUtil.Left(value, 31); }
}
//-------------------------------------------------------------------
public override bool SetWorksheetAttr(SaMsExcelStyleAttr attr)
{
ClearErrorState();
try
{
// ToDo OpenXml SetWorksheetAttr
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
//-------------------------------------------------------------------
// Worksheet Page Setup.
public override bool SetPageSetup(SaMsExcelPageSetup_Config pageSetupConfig)
{
//---------------------------------------------------------------
// Page setup options:
// ActiveSheet.PageSetup
// .PrintTitleRows = "$4:$4"
// .PrintTitleColumns = ""
// .PrintArea = ""
// .LeftHeader = ""
// .CenterHeader = ""
// .RightHeader = ""
// .LeftFooter = ""
// .CenterFooter = ""
// .RightFooter = ""
// .LeftMargin = Application.InchesToPoints(0.708661417322835)
// .RightMargin = Application.InchesToPoints(0.708661417322835)
// .TopMargin = Application.InchesToPoints(0.748031496062992)
// .BottomMargin = Application.InchesToPoints(0.748031496062992)
// .HeaderMargin = Application.InchesToPoints(0.31496062992126)
// .FooterMargin = Application.InchesToPoints(0.31496062992126)
// .PrintHeadings = False
// .PrintGridlines = False
// .PrintComments = xlPrintNoComments
// .PrintQuality = 600
// .CenterHorizontally = False
// .CenterVertically = False
// .Orientation = xlPortrait
// .Draft = False
// .PaperSize = xlPaperA4
// .FirstPageNumber = xlAutomatic
// .Order = xlDownThenOver
// .BlackAndWhite = False
// .Zoom = 100
// .PrintErrors = xlPrintErrorsDisplayed
// .OddAndEvenPagesHeaderFooter = False
// .DifferentFirstPageHeaderFooter = False
// .ScaleWithDocHeaderFooter = True
// .AlignMarginsHeaderFooter = True
// .EvenPage.LeftHeader.Text = ""
// .EvenPage.CenterHeader.Text = ""
// .EvenPage.RightHeader.Text = ""
// .EvenPage.LeftFooter.Text = ""
// .EvenPage.CenterFooter.Text = ""
// .EvenPage.RightFooter.Text = ""
// .FirstPage.LeftHeader.Text = ""
// .FirstPage.CenterHeader.Text = ""
// .FirstPage.RightHeader.Text = ""
// .FirstPage.LeftFooter.Text = ""
// .FirstPage.CenterFooter.Text = ""
// .FirstPage.RightFooter.Text = ""
//---------------------------------------------------------------
// Negative values leave current value.
ClearErrorState();
if (worksheet == null) return false;
try
{
// Page margins - must be before the Page Setup in the worksheet.
PageMargins pageMargins = worksheet.WorksheetPart.Worksheet.GetFirstChild<PageMargins>();
if (pageMargins == null)
{
pageMargins = new PageMargins();
worksheet.WorksheetPart.Worksheet.AppendChild(pageMargins);
}
// Page Setup.
PageSetupProperties pageSetupProperties = worksheet.WorksheetPart.Worksheet.SheetProperties.PageSetupProperties;
PageSetup pageSetup = worksheet.WorksheetPart.Worksheet.GetFirstChild<PageSetup>();
if (pageSetup == null)
{
pageSetup = new PageSetup();
worksheet.WorksheetPart.Worksheet.AppendChild(pageSetup);
}
if (pageSetupConfig.Orientation == SaXlPageOrientation.xlLandscape)
pageSetup.Orientation = OrientationValues.Landscape;
else if (pageSetupConfig.Orientation == SaXlPageOrientation.xlPortrait)
pageSetup.Orientation = OrientationValues.Portrait;
// ToDo OpenXML Headers and footers.
//pageSetup.LeftHeader = pageSetupConfig.HeaderLeft;
//pageSetup.CenterHeader = pageSetupConfig.HeaderCenter;
//pageSetup.RightHeader = pageSetupConfig.HeaderRight;
//pageSetup.LeftFooter = pageSetupConfig.FooterLeft;
//pageSetup.CenterFooter = pageSetupConfig.FooterCenter;
//pageSetup.RightFooter = pageSetupConfig.FooterRight;
// Margins.
if (pageSetupConfig.MarginLeft > 0) pageMargins.Left = ToPoints(pageSetupConfig.MarginLeft, pageSetupConfig.Unit, false);
if (pageSetupConfig.MarginRight > 0) pageMargins.Right = ToPoints(pageSetupConfig.MarginRight, pageSetupConfig.Unit, false);
if (pageSetupConfig.MarginTop > 0) pageMargins.Top = ToPoints(pageSetupConfig.MarginTop, pageSetupConfig.Unit, true);
if (pageSetupConfig.MarginBottom > 0) pageMargins.Bottom = ToPoints(pageSetupConfig.MarginBottom, pageSetupConfig.Unit, true);
if (pageSetupConfig.MarginHeader > 0) pageMargins.Header = ToPoints(pageSetupConfig.MarginHeader, pageSetupConfig.Unit, true);
if (pageSetupConfig.MarginFooter > 0) pageMargins.Footer = ToPoints(pageSetupConfig.MarginFooter, pageSetupConfig.Unit, true);
/*
* ToDo OpenXML PrintTitleRows/Columns
// Print Title Rows.
if (pageSetupConfig.PrintTitleRowFrom > 0 && pageSetupConfig.PrintTitleRowTo > 0)
// Prefix with '$' to fix row value.(?)
pageSetup.PrintTitleRows = "$" + GetRowSuffix((uint)pageSetupConfig.PrintTitleRowFrom) + ":$" + GetRowSuffix((uint)pageSetupConfig.PrintTitleRowTo);
else if (pageSetupConfig.PrintTitleRowFrom == 0 && pageSetupConfig.PrintTitleRowTo == 0)
pageSetup.PrintTitleRows = "";
// Print Title Columns.
if (pageSetupConfig.PrintTitleColFrom > 0 && pageSetupConfig.PrintTitleColTo > 0)
pageSetup.PrintTitleColumns = "$" + GetColumnPrefix((uint)pageSetupConfig.PrintTitleColFrom) + ":$" + GetColumnPrefix((uint)pageSetupConfig.PrintTitleColTo);
else if (pageSetupConfig.PrintTitleColFrom == 0 && pageSetupConfig.PrintTitleColTo == 0)
pageSetup.PrintTitleColumns = "";
*/
/*
// ToDo OpenXML Zoom and 'Fit to' options.
if (pageSetupConfig.Zoom > 0)
pageSetup.Zoom = pageSetupConfig.Zoom;
else if (pageSetupConfig.FitToPagesTall > 0 || pageSetupConfig.FitToPagesWide > 0)
{
pageSetup.FitToPagesWide = Math.Min(0, pageSetupConfig.FitToPagesWide);
pageSetup.FitToPagesTall = Math.Min(0, pageSetupConfig.FitToPagesTall);
pageSetup.Zoom = 0;
}
*/
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
public override bool SetPageBreak(uint colPos, uint rowPos)
{
ClearErrorState();
if (worksheet == null) return false;
try
{
/*
* ToDo OpenXML Set page break
String cellId = GetCellId(colPos, rowPos);
Range range = worksheet.get_Range(cellId);
worksheet.HPageBreaks.Add(range);
worksheet.VPageBreaks.Add(range);
*/
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
//-------------------------------------------------------------------
public bool SelectRange()
{
// ToDo OpenXML Is SelectRange even relevant?
return false;
}
//-------------------------------------------------------------------
// C o l u m n s
//-------------------------------------------------------------------
private Column GetColumnByPos(uint columnPos)
{
if (worksheet.ActiveColumnPos != columnPos)
{
// ToDo OpenXML GetColumnByPos.
//Column column = worksheet.WorksheetPart.col
}
return worksheet.ActiveColumn;
}
public override uint ActiveColPos
{
get
{
if (worksheet == null) return 0;
try
{
return worksheet.ActiveColumnPos;
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return 0;
}
}
public override double GetColWidth(uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
{
double columnWidth = 0.0;
try
{
// ToDo OpenXML GetColWidth.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return columnWidth;
}
public override bool SetColWidth(uint colPos, double columnWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
{
ClearErrorState();
try
{
// ToDo OpenXML SetColWidth.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
//-------------------------------------------------------------------
// R o w s
//-------------------------------------------------------------------
public override uint FirstRowPos { get { return (uint)(0); } }
public override uint LastRowPos { get { return (uint)(0); } }
//-------------------------------------------------------------------
public override uint ActiveRowPos
{
get
{
try
{
// ToDo OpenXML GetActiveRowPos.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return 0;
}
}
public override List<DataValue> GetRowValues(uint rowPos, int maxColumns = 0)
{
List<DataValue> values = new List<DataValue>();
return values;
}
public override double GetRowHeight(uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
{
double rowHeight = 0.0;
try
{
// ToDo OpenXML GetRowHeight.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return rowHeight;
}
public override bool SetRowHeight(uint rowPos, double rowHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
{
ClearErrorState();
try
{
// ToDo OpenXML SetRowHeight.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
//-------------------------------------------------------------------
// C e l l s
//-------------------------------------------------------------------
public override void SetActiveCell(uint colPos, uint rowPos)
{
// ToDo OpenXML SetActiveCell.
}
public override String GetCellFormula(uint colPos, uint rowPos)
{
// ToDo OpenXML GetCellFormula.
return "";
}
public override String GetCellText(uint colPos, uint rowPos, bool trimWhitespace = true)
{
// ToDo OpenXML GetCellText.
return "";
}
public override DataValue GetCellValue(uint colPos, uint rowPos)
{
// ToDo OpenXML GetCellDataValue.
return new DataValue();
}
//-------------------------------------------------------------------
public override bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelStyleAttr attr)
{
// ToDo OpenXML SetCellFormula.
return true;
}
public override bool SetCellValue(uint colPos, uint rowPos, DataValue value, SaMsExcelStyleAttr attr)
{
// ToDo OpenXML SetCellValue.
return true;
}
//-------------------------------------------------------------------
// Cell attributes.
public override bool SetRangeAttr(SaMsExcelRange range, SaMsExcelStyleAttr attr)
{
ClearErrorState();
try
{
// ToDo OpenXML SetRangeAttr.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
private bool SetRangeAttr(Range oRange, SaMsExcelStyleAttr attr)
{
ClearErrorState();
try
{
// ToDo OpenXML SetRangeAttr.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
//-------------------------------------------------------------------
// I m a g e s
//-------------------------------------------------------------------
// Add image to sheet.
public override bool InsertImage(SaMsExcelImage_Config imageConfig)
{
ClearErrorState();
if (worksheet == null) return false;
try
{
// ToDo OpenXML InsertImage.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
//-------------------------------------------------------------------
public override bool FreezePanes(uint colPos, uint rowPos)
{
ClearErrorState();
try
{
// ToDo OpenXML FreezePanes.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
//-------------------------------------------------------------------
public override bool AutoFitRows(SaMsExcelRange range)
{
ClearErrorState();
try
{
// ToDo OpenXML AutoFit.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
//-------------------------------------------------------------------
public override bool SelectRange(SaMsExcelRange range)
{
ClearErrorState();
try
{
// ToDo OpenXML SelectRange.
}
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
return OK;
}
//-------------------------------------------------------------------
}
//=======================================================================
}