Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/MiniExcel/OpenXml/Constants/WorksheetXml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Globalization;
using MiniExcelLibs.Attributes;
using System.Linq;

namespace MiniExcelLibs.OpenXml.Constants
{
Expand Down Expand Up @@ -46,8 +47,17 @@ internal static string StartRow(int rowIndex)
internal const string EndRow = "</x:row>";

internal const string StartCols = "<x:cols>";
internal static string Column(int? colIndex, double? columnWidth)
=> $@"<x:col min=""{colIndex.GetValueOrDefault() + 1}"" max=""{colIndex.GetValueOrDefault() + 1}"" width=""{columnWidth?.ToString(CultureInfo.InvariantCulture)}"" customWidth=""1"" />";
internal static string Column(int colIndex, double columnWidth)
=> $@"<x:col min=""{colIndex}"" max=""{colIndex}"" width=""{columnWidth.ToString(CultureInfo.InvariantCulture)}"" customWidth=""1"" />";


private static readonly int _maxColumnLength = Column(int.MaxValue, double.MaxValue).Length;

public static int GetColumnPlaceholderLength(int columnCount)
{
return StartCols.Length + (_maxColumnLength * columnCount) + EndCols.Length;
}

internal const string EndCols = "</x:cols>";

internal static string EmptyCell(string cellReference, string styleIndex)
Expand Down
105 changes: 84 additions & 21 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO.Compression;
using System.Linq;
using System.Text;
Expand Down Expand Up @@ -104,6 +105,8 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr
var yIndex = 1;
int maxColumnIndex;
int maxRowIndex;
ExcelWidthCollection widths = null;
long columnWidthsPlaceholderPosition = 0;
{
if (_configuration.FastMode)
{
Expand All @@ -122,7 +125,15 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr
//sheet view
await writer.WriteAsync(GetSheetViews());

await WriteColumnsWidthsAsync(writer, props);
if (_configuration.EnableAutoWidth)
{
columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, props);
widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props);
}
else
{
await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props));
}

await writer.WriteAsync(WorksheetXml.StartSheetData);
int fieldCount = reader.FieldCount;
Expand All @@ -139,7 +150,7 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr
for (int i = 0; i < fieldCount; i++)
{
var cellValue = reader.GetValue(i);
await WriteCellAsync(writer, yIndex, xIndex, cellValue, props[i]);
await WriteCellAsync(writer, yIndex, xIndex, cellValue, props[i], widths);
xIndex++;
}
await writer.WriteAsync(WorksheetXml.EndRow);
Expand All @@ -163,6 +174,10 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr
{
await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition);
}
if (_configuration.EnableAutoWidth)
{
await OverWriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths.Columns);
}
}

private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter writer, IEnumerable values)
Expand Down Expand Up @@ -248,7 +263,17 @@ private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter wri
await writer.WriteAsync(GetSheetViews());

//cols:width
await WriteColumnsWidthsAsync(writer, props);
ExcelWidthCollection widths = null;
long columnWidthsPlaceholderPosition = 0;
if (_configuration.EnableAutoWidth)
{
columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, props);
widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props);
}
else
{
await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props));
}

//header
await writer.WriteAsync(WorksheetXml.StartSheetData);
Expand All @@ -266,13 +291,13 @@ private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter wri
switch (mode)
{
case "IDictionary<string, object>": //Dapper Row
maxRowIndex = await GenerateSheetByColumnInfoAsync<IDictionary<string, object>>(writer, enumerator, props, xIndex, yIndex);
maxRowIndex = await GenerateSheetByColumnInfoAsync<IDictionary<string, object>>(writer, enumerator, props, widths, xIndex, yIndex);
break;
case "IDictionary":
maxRowIndex = await GenerateSheetByColumnInfoAsync<IDictionary>(writer, enumerator, props, xIndex, yIndex);
maxRowIndex = await GenerateSheetByColumnInfoAsync<IDictionary>(writer, enumerator, props, widths, xIndex, yIndex);
break;
case "Properties":
maxRowIndex = await GenerateSheetByColumnInfoAsync<object>(writer, enumerator, props, xIndex, yIndex);
maxRowIndex = await GenerateSheetByColumnInfoAsync<object>(writer, enumerator, props, widths, xIndex, yIndex);
break;
default:
throw new NotImplementedException($"Type {values.GetType().FullName} is not implemented. Please open an issue.");
Expand All @@ -293,6 +318,10 @@ private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter wri
{
await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition);
}
if (_configuration.EnableAutoWidth)
{
await OverWriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths.Columns);
}
}

private async Task GenerateSheetByDataTableAsync(MiniExcelAsyncStreamWriter writer, DataTable value)
Expand All @@ -318,7 +347,17 @@ private async Task GenerateSheetByDataTableAsync(MiniExcelAsyncStreamWriter writ
//sheet view
await writer.WriteAsync(GetSheetViews());

await WriteColumnsWidthsAsync(writer, props);
ExcelWidthCollection widths = null;
long columnWidthsPlaceholderPosition = 0;
if (_configuration.EnableAutoWidth)
{
columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, props);
widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props);
}
else
{
await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props));
}

await writer.WriteAsync(WorksheetXml.StartSheetData);
if (_printHeader)
Expand All @@ -344,7 +383,7 @@ private async Task GenerateSheetByDataTableAsync(MiniExcelAsyncStreamWriter writ
for (int j = 0; j < value.Columns.Count; j++)
{
var cellValue = value.Rows[i][j];
await WriteCellAsync(writer, yIndex, xIndex, cellValue, props[j]);
await WriteCellAsync(writer, yIndex, xIndex, cellValue, props[j], widths);
xIndex++;
}
await writer.WriteAsync(WorksheetXml.EndRow);
Expand All @@ -357,25 +396,48 @@ private async Task GenerateSheetByDataTableAsync(MiniExcelAsyncStreamWriter writ
{
await writer.WriteAsync(WorksheetXml.Autofilter(GetDimensionRef(maxRowIndex, maxColumnIndex)));
}
if (_configuration.EnableAutoWidth)
{
await OverWriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths.Columns);
}

await writer.WriteAsync(WorksheetXml.EndWorksheet);
}

private static async Task WriteColumnsWidthsAsync(MiniExcelAsyncStreamWriter writer, IEnumerable<ExcelColumnInfo> props)
private async Task<long> WriteColumnWidthPlaceholdersAsync(MiniExcelAsyncStreamWriter writer, ICollection<ExcelColumnInfo> props)
{
var ecwProps = props.Where(x => x?.ExcelColumnWidth != null).ToList();
if (ecwProps.Count <= 0)
{
return;
}
var placeholderPosition = await writer.FlushAsync();
await writer.WriteWhitespaceAsync(WorksheetXml.GetColumnPlaceholderLength(props.Count));
return placeholderPosition;
}

await writer.WriteAsync(WorksheetXml.StartCols);
private async Task OverWriteColumnWidthPlaceholdersAsync(MiniExcelAsyncStreamWriter writer, long placeholderPosition, IEnumerable<ExcelColumnWidth> columnWidths)
{
var position = await writer.FlushAsync();

foreach (var p in ecwProps)
writer.SetPosition(placeholderPosition);
await WriteColumnsWidthsAsync(writer, columnWidths);

await writer.FlushAsync();
writer.SetPosition(position);
}

private async Task WriteColumnsWidthsAsync(MiniExcelAsyncStreamWriter writer, IEnumerable<ExcelColumnWidth> columnWidths)
{
var hasWrittenStart = false;
foreach (var column in columnWidths)
{
await writer.WriteAsync(WorksheetXml.Column(p.ExcelColumnIndex, p.ExcelColumnWidth));
if (!hasWrittenStart)
{
await writer.WriteAsync(WorksheetXml.StartCols);
hasWrittenStart = true;
}
await writer.WriteAsync(WorksheetXml.Column(column.Index, column.Width));
}
if (!hasWrittenStart)
{
return;
}

await writer.WriteAsync(WorksheetXml.EndCols);
}

Expand All @@ -401,7 +463,7 @@ private static async Task PrintHeaderAsync(MiniExcelAsyncStreamWriter writer, Li
await writer.WriteAsync(WorksheetXml.EndRow);
}

private async Task<int> GenerateSheetByColumnInfoAsync<T>(MiniExcelAsyncStreamWriter writer, IEnumerator value, List<ExcelColumnInfo> props, int xIndex = 1, int yIndex = 1)
private async Task<int> GenerateSheetByColumnInfoAsync<T>(MiniExcelAsyncStreamWriter writer, IEnumerator value, List<ExcelColumnInfo> props, ExcelWidthCollection widthCollection, int xIndex = 1, int yIndex = 1)
{
var isDic = typeof(T) == typeof(IDictionary);
var isDapperRow = typeof(T) == typeof(IDictionary<string, object>);
Expand Down Expand Up @@ -436,7 +498,7 @@ private async Task<int> GenerateSheetByColumnInfoAsync<T>(MiniExcelAsyncStreamWr
cellValue = p.Property.GetValue(v);
}

await WriteCellAsync(writer, yIndex, cellIndex, cellValue, p);
await WriteCellAsync(writer, yIndex, cellIndex, cellValue, p, widthCollection);

cellIndex++;
}
Expand All @@ -453,7 +515,7 @@ private static async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, stri
await writer.WriteAsync(WorksheetXml.Cell(cellReference, "str", "1", ExcelOpenXmlUtils.EncodeXML(columnName)));
}

private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowIndex, int cellIndex, object value, ExcelColumnInfo p)
private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowIndex, int cellIndex, object value, ExcelColumnInfo p, ExcelWidthCollection widthCollection)
{
var columnReference = ExcelOpenXmlUtils.ConvertXyToCell(cellIndex, rowIndex);
var valueIsNull = value is null || value is DBNull;
Expand All @@ -474,6 +536,7 @@ private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowInde
/*Prefix and suffix blank space will lost after SaveAs #294*/
var preserveSpace = cellValue != null && (cellValue.StartsWith(" ", StringComparison.Ordinal) || cellValue.EndsWith(" ", StringComparison.Ordinal));
await writer.WriteAsync(WorksheetXml.Cell(columnReference, dataType, styleIndex, cellValue, preserveSpace: preserveSpace, columnType: columnType));
widthCollection?.AdjustWidth(cellIndex, cellValue);
}

private async Task GenerateEndXmlAsync(CancellationToken cancellationToken)
Expand Down
Loading