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
9 changes: 9 additions & 0 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr
}
maxColumnIndex = props.Count;

//sheet view
await writer.WriteAsync(GetSheetViews());

await WriteColumnsWidthsAsync(writer, props);

await writer.WriteAsync(WorksheetXml.StartSheetData);
Expand Down Expand Up @@ -241,6 +244,9 @@ private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter wri
await writer.WriteAsync(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, maxColumnIndex)));
}

//sheet view
await writer.WriteAsync(GetSheetViews());

//cols:width
await WriteColumnsWidthsAsync(writer, props);

Expand Down Expand Up @@ -309,6 +315,9 @@ private async Task GenerateSheetByDataTableAsync(MiniExcelAsyncStreamWriter writ
props.Add(prop);
}

//sheet view
await writer.WriteAsync(GetSheetViews());

await WriteColumnsWidthsAsync(writer, props);

await writer.WriteAsync(WorksheetXml.StartSheetData);
Expand Down
97 changes: 97 additions & 0 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.DefaultOpenXml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,103 @@ private ExcellSheetInfo GetSheetInfos(string sheetName)

return info;
}

private string GetSheetViews()
{
// exit early if no style to write
if (_configuration.FreezeRowCount <= 0 && _configuration.FreezeColumnCount <= 0)
{
return string.Empty;
}

var sb = new StringBuilder();

// start sheetViews
sb.Append(WorksheetXml.StartSheetViews);
sb.Append(WorksheetXml.StartSheetView());

// Write panes
sb.Append(GetPanes());

// end sheetViews
sb.Append(WorksheetXml.EndSheetView);
sb.Append(WorksheetXml.EndSheetViews);

return sb.ToString();
}

private string GetPanes()
{

var sb = new StringBuilder();

string activePane;
if (_configuration.FreezeColumnCount > 0 && _configuration.FreezeRowCount > 0)
{
activePane = "bottomRight";
}
else if (_configuration.FreezeColumnCount > 0)
{
activePane = "topRight";
}
else
{
activePane = "bottomLeft";
}
sb.Append(
WorksheetXml.StartPane(
xSplit: _configuration.FreezeColumnCount > 0 ? _configuration.FreezeColumnCount : (int?)null,
ySplit: _configuration.FreezeRowCount > 0 ? _configuration.FreezeRowCount : (int?)null,
topLeftCell: ExcelOpenXmlUtils.ConvertXyToCell(
_configuration.FreezeColumnCount + 1,
_configuration.FreezeRowCount + 1
),
activePane: activePane,
state: "frozen"
)
);

// write pane selections
if (_configuration.FreezeColumnCount > 0 && _configuration.FreezeRowCount > 0)
{
// freeze row and column
/*
<selection pane="topRight" activeCell="B1" sqref="B1"/>
<selection pane="bottomLeft" activeCell="A3" sqref="A3"/>
<selection pane="bottomRight" activeCell="B3" sqref="B3"/>
*/
var cellTR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount + 1, 1);
sb.Append(WorksheetXml.PaneSelection("topRight", cellTR, cellTR));

var cellBL = ExcelOpenXmlUtils.ConvertXyToCell(1, _configuration.FreezeRowCount + 1);
sb.Append(WorksheetXml.PaneSelection("bottomLeft", cellBL, cellBL));

var cellBR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount + 1, _configuration.FreezeRowCount + 1);
sb.Append(WorksheetXml.PaneSelection("bottomRight", cellBR, cellBR));
}
else if (_configuration.FreezeColumnCount > 0)
{
// freeze column
/*
<selection pane="topRight" activeCell="A1" sqref="A1"/>
*/
var cellTR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount, 1);
sb.Append(WorksheetXml.PaneSelection("topRight", cellTR, cellTR));

}
else
{
// freeze row
/*
<selection pane="bottomLeft"/>
*/
sb.Append(WorksheetXml.PaneSelection("bottomLeft", null, null));

}

return sb.ToString();

}

private ExcelColumnInfo GetColumnInfosFromDynamicConfiguration(string columnName)
{
Expand Down
91 changes: 3 additions & 88 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ private void GenerateSheetByIDataReader(MiniExcelStreamWriter writer, IDataReade
maxColumnIndex = props.Count;

//sheet view
WriteSheetViews(writer);
writer.Write(GetSheetViews());

WriteColumnsWidths(writer, props);

Expand Down Expand Up @@ -279,7 +279,7 @@ private void GenerateSheetByEnumerable(MiniExcelStreamWriter writer, IEnumerable
}

//sheet view
WriteSheetViews(writer);
writer.Write(GetSheetViews());

//cols:width
WriteColumnsWidths(writer, props);
Expand Down Expand Up @@ -352,7 +352,7 @@ private void GenerateSheetByDataTable(MiniExcelStreamWriter writer, DataTable va
}

//sheet view
WriteSheetViews(writer);
writer.Write(GetSheetViews());

WriteColumnsWidths(writer, props);

Expand Down Expand Up @@ -411,91 +411,6 @@ private static void WriteColumnsWidths(MiniExcelStreamWriter writer, IEnumerable
writer.Write(WorksheetXml.EndCols);
}

private void WriteSheetViews(MiniExcelStreamWriter writer) {
// exit early if no style to write
if (_configuration.FreezeRowCount <= 0 && _configuration.FreezeColumnCount <= 0)
{
return;
}

// start sheetViews
writer.Write(WorksheetXml.StartSheetViews);
writer.Write(WorksheetXml.StartSheetView());

// Write panes
WritePanes(writer);

// end sheetViews
writer.Write(WorksheetXml.EndSheetView);
writer.Write(WorksheetXml.EndSheetViews);
}

private void WritePanes(MiniExcelStreamWriter writer) {

string activePane;
if (_configuration.FreezeColumnCount > 0 && _configuration.FreezeRowCount > 0)
{
activePane = "bottomRight";
}
else if (_configuration.FreezeColumnCount > 0)
{
activePane = "topRight";
}
else
{
activePane = "bottomLeft";
}
writer.Write( WorksheetXml.StartPane(
xSplit: _configuration.FreezeColumnCount > 0 ? _configuration.FreezeColumnCount : (int?)null,
ySplit: _configuration.FreezeRowCount > 0 ? _configuration.FreezeRowCount : (int?)null,
topLeftCell: ExcelOpenXmlUtils.ConvertXyToCell(
_configuration.FreezeColumnCount + 1,
_configuration.FreezeRowCount + 1
),
activePane: activePane,
state: "frozen"
) );

// write pane selections
if (_configuration.FreezeColumnCount > 0 && _configuration.FreezeRowCount > 0)
{
// freeze row and column
/*
<selection pane="topRight" activeCell="B1" sqref="B1"/>
<selection pane="bottomLeft" activeCell="A3" sqref="A3"/>
<selection pane="bottomRight" activeCell="B3" sqref="B3"/>
*/
var cellTR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount+1, 1);
writer.Write(WorksheetXml.PaneSelection("topRight", cellTR, cellTR));

var cellBL = ExcelOpenXmlUtils.ConvertXyToCell(1, _configuration.FreezeRowCount+1);
writer.Write(WorksheetXml.PaneSelection("bottomLeft", cellBL, cellBL));

var cellBR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount+1, _configuration.FreezeRowCount+1);
writer.Write(WorksheetXml.PaneSelection("bottomRight", cellBR, cellBR));
}
else if ( _configuration.FreezeColumnCount > 0 )
{
// freeze column
/*
<selection pane="topRight" activeCell="A1" sqref="A1"/>
*/
var cellTR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount, 1);
writer.Write(WorksheetXml.PaneSelection("topRight", cellTR, cellTR));

}
else
{
// freeze row
/*
<selection pane="bottomLeft"/>
*/
writer.Write(WorksheetXml.PaneSelection("bottomLeft", null, null));

}

}

private static void PrintHeader(MiniExcelStreamWriter writer, List<ExcelColumnInfo> props)
{
var xIndex = 1;
Expand Down
64 changes: 64 additions & 0 deletions tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,70 @@ public async Task SaveAsByIEnumerableIDictionaryWithDynamicConfiguration()
File.Delete(path);
}


[Fact()]
public async Task SaveAsFrozenRowsAndColumnsTest()
{

var config = new OpenXmlConfiguration
{
FreezeRowCount = 1,
FreezeColumnCount = 2
};

{
// Test enumerable
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
await MiniExcel.SaveAsAsync(
path,
new[] {
new { Column1 = "MiniExcel", Column2 = 1 },
new { Column1 = "Github", Column2 = 2}
},
configuration: config
);

using (var stream = File.OpenRead(path))
{
var rows = stream.Query(useHeaderRow: true).ToList();

Assert.Equal("MiniExcel", rows[0].Column1);
Assert.Equal(1, rows[0].Column2);
Assert.Equal("Github", rows[1].Column1);
Assert.Equal(2, rows[1].Column2);
}

Assert.Equal("A1:B3", Helpers.GetFirstSheetDimensionRefValue(path));
File.Delete(path);
}

{
// test table
var table = new DataTable();
{
table.Columns.Add("a", typeof(string));
table.Columns.Add("b", typeof(decimal));
table.Columns.Add("c", typeof(bool));
table.Columns.Add("d", typeof(DateTime));
table.Rows.Add("some text", 1234567890, true, DateTime.Now);
table.Rows.Add(@"<test>Hello World</test>", -1234567890, false, DateTime.Now.Date);
}
var pathTable = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
await MiniExcel.SaveAsAsync(pathTable, table, configuration: config);

Assert.Equal("A1:D3", Helpers.GetFirstSheetDimensionRefValue(pathTable));


// data reader
var reader = table.CreateDataReader();
var pathReader = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");

await MiniExcel.SaveAsAsync(pathReader, reader, configuration: config);
Assert.Equal("A1:D3", Helpers.GetFirstSheetDimensionRefValue(pathTable));
}

}

[Fact()]
public async Task SaveAsByDapperRows()
{
Expand Down
18 changes: 10 additions & 8 deletions tests/MiniExcelTests/MiniExcelOpenXmlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public void QueryCastToIDictionary()

}
}

[Fact]
public void QueryRangeToIDictionary()
{
Expand Down Expand Up @@ -201,7 +201,7 @@ public void CenterEmptyRowsQueryTest()

Assert.Equal(null, rows[2].A);
Assert.Equal(2, rows[2].B);
Assert.Equal(null, rows[2].C);
Assert.Equal(null, rows[2].C);
Assert.Equal(4, rows[2].D);

Assert.Equal(null, rows[3].A);
Expand Down Expand Up @@ -860,7 +860,8 @@ public void SaveAsByIEnumerableIDictionary()
}

[Fact()]
public void SaveAsFrozenRowsAndColumnsTest() {
public void SaveAsFrozenRowsAndColumnsTest()
{

var config = new OpenXmlConfiguration
{
Expand All @@ -880,7 +881,8 @@ public void SaveAsFrozenRowsAndColumnsTest() {
configuration: config
);

using (var stream = File.OpenRead(path)) {
using (var stream = File.OpenRead(path))
{
var rows = stream.Query(useHeaderRow: true).ToList();

Assert.Equal("MiniExcel", rows[0].Column1);
Expand All @@ -890,9 +892,9 @@ public void SaveAsFrozenRowsAndColumnsTest() {
}

Assert.Equal("A1:B3", Helpers.GetFirstSheetDimensionRefValue(path));
//File.Delete(path);
File.Delete(path);
}

{
// test table
var table = new DataTable();
Expand All @@ -905,7 +907,7 @@ public void SaveAsFrozenRowsAndColumnsTest() {
table.Rows.Add(@"<test>Hello World</test>", -1234567890, false, DateTime.Now.Date);
}
var pathTable = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
MiniExcel.SaveAs(pathTable, table, configuration: config );
MiniExcel.SaveAs(pathTable, table, configuration: config);

Assert.Equal("A1:D3", Helpers.GetFirstSheetDimensionRefValue(pathTable));

Expand Down Expand Up @@ -1392,7 +1394,7 @@ public void DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingDataTable()
{
table.Columns.Add("Column1", typeof(string));
table.Columns.Add("Column2", typeof(int));
table.Columns.Add("Column3", typeof(DateTime));
table.Columns.Add("Column3", typeof(DateTime));
table.Columns.Add("Column4", typeof(DateOnly));
table.Rows.Add("MiniExcel", 1, dateTime, onlyDate);
table.Rows.Add("Github", 2, dateTime, onlyDate);
Expand Down