mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-11-29 18:38:08 +08:00
Async implementation of freezing top row (#684)
* Add async implementation of frozen rows and columns * Add unit tests for async implementation of frozen rows and columns * Fix formatting and delete temp file in unit test * move freezing top row implementation to DefaultOpenXml.cs
This commit is contained in:
parent
a0797a53f6
commit
92b295d4b2
@ -119,6 +119,9 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
}
|
}
|
||||||
maxColumnIndex = props.Count;
|
maxColumnIndex = props.Count;
|
||||||
|
|
||||||
|
//sheet view
|
||||||
|
await writer.WriteAsync(GetSheetViews());
|
||||||
|
|
||||||
await WriteColumnsWidthsAsync(writer, props);
|
await WriteColumnsWidthsAsync(writer, props);
|
||||||
|
|
||||||
await writer.WriteAsync(WorksheetXml.StartSheetData);
|
await writer.WriteAsync(WorksheetXml.StartSheetData);
|
||||||
@ -241,6 +244,9 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
await writer.WriteAsync(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, maxColumnIndex)));
|
await writer.WriteAsync(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, maxColumnIndex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sheet view
|
||||||
|
await writer.WriteAsync(GetSheetViews());
|
||||||
|
|
||||||
//cols:width
|
//cols:width
|
||||||
await WriteColumnsWidthsAsync(writer, props);
|
await WriteColumnsWidthsAsync(writer, props);
|
||||||
|
|
||||||
@ -309,6 +315,9 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
props.Add(prop);
|
props.Add(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sheet view
|
||||||
|
await writer.WriteAsync(GetSheetViews());
|
||||||
|
|
||||||
await WriteColumnsWidthsAsync(writer, props);
|
await WriteColumnsWidthsAsync(writer, props);
|
||||||
|
|
||||||
await writer.WriteAsync(WorksheetXml.StartSheetData);
|
await writer.WriteAsync(WorksheetXml.StartSheetData);
|
||||||
|
@ -83,6 +83,103 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
|
|
||||||
return info;
|
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)
|
private ExcelColumnInfo GetColumnInfosFromDynamicConfiguration(string columnName)
|
||||||
{
|
{
|
||||||
|
@ -152,7 +152,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
maxColumnIndex = props.Count;
|
maxColumnIndex = props.Count;
|
||||||
|
|
||||||
//sheet view
|
//sheet view
|
||||||
WriteSheetViews(writer);
|
writer.Write(GetSheetViews());
|
||||||
|
|
||||||
WriteColumnsWidths(writer, props);
|
WriteColumnsWidths(writer, props);
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
}
|
}
|
||||||
|
|
||||||
//sheet view
|
//sheet view
|
||||||
WriteSheetViews(writer);
|
writer.Write(GetSheetViews());
|
||||||
|
|
||||||
//cols:width
|
//cols:width
|
||||||
WriteColumnsWidths(writer, props);
|
WriteColumnsWidths(writer, props);
|
||||||
@ -352,7 +352,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
}
|
}
|
||||||
|
|
||||||
//sheet view
|
//sheet view
|
||||||
WriteSheetViews(writer);
|
writer.Write(GetSheetViews());
|
||||||
|
|
||||||
WriteColumnsWidths(writer, props);
|
WriteColumnsWidths(writer, props);
|
||||||
|
|
||||||
@ -411,91 +411,6 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
writer.Write(WorksheetXml.EndCols);
|
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)
|
private static void PrintHeader(MiniExcelStreamWriter writer, List<ExcelColumnInfo> props)
|
||||||
{
|
{
|
||||||
var xIndex = 1;
|
var xIndex = 1;
|
||||||
|
@ -894,6 +894,70 @@ namespace MiniExcelLibs.Tests
|
|||||||
File.Delete(path);
|
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()]
|
[Fact()]
|
||||||
public async Task SaveAsByDapperRows()
|
public async Task SaveAsByDapperRows()
|
||||||
{
|
{
|
||||||
|
@ -166,7 +166,7 @@ namespace MiniExcelLibs.Tests
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void QueryRangeToIDictionary()
|
public void QueryRangeToIDictionary()
|
||||||
{
|
{
|
||||||
@ -201,7 +201,7 @@ namespace MiniExcelLibs.Tests
|
|||||||
|
|
||||||
Assert.Equal(null, rows[2].A);
|
Assert.Equal(null, rows[2].A);
|
||||||
Assert.Equal(2, rows[2].B);
|
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(4, rows[2].D);
|
||||||
|
|
||||||
Assert.Equal(null, rows[3].A);
|
Assert.Equal(null, rows[3].A);
|
||||||
@ -860,7 +860,8 @@ namespace MiniExcelLibs.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact()]
|
[Fact()]
|
||||||
public void SaveAsFrozenRowsAndColumnsTest() {
|
public void SaveAsFrozenRowsAndColumnsTest()
|
||||||
|
{
|
||||||
|
|
||||||
var config = new OpenXmlConfiguration
|
var config = new OpenXmlConfiguration
|
||||||
{
|
{
|
||||||
@ -880,7 +881,8 @@ namespace MiniExcelLibs.Tests
|
|||||||
configuration: config
|
configuration: config
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var stream = File.OpenRead(path)) {
|
using (var stream = File.OpenRead(path))
|
||||||
|
{
|
||||||
var rows = stream.Query(useHeaderRow: true).ToList();
|
var rows = stream.Query(useHeaderRow: true).ToList();
|
||||||
|
|
||||||
Assert.Equal("MiniExcel", rows[0].Column1);
|
Assert.Equal("MiniExcel", rows[0].Column1);
|
||||||
@ -890,9 +892,9 @@ namespace MiniExcelLibs.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal("A1:B3", Helpers.GetFirstSheetDimensionRefValue(path));
|
Assert.Equal("A1:B3", Helpers.GetFirstSheetDimensionRefValue(path));
|
||||||
//File.Delete(path);
|
File.Delete(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// test table
|
// test table
|
||||||
var table = new DataTable();
|
var table = new DataTable();
|
||||||
@ -905,7 +907,7 @@ namespace MiniExcelLibs.Tests
|
|||||||
table.Rows.Add(@"<test>Hello World</test>", -1234567890, false, DateTime.Now.Date);
|
table.Rows.Add(@"<test>Hello World</test>", -1234567890, false, DateTime.Now.Date);
|
||||||
}
|
}
|
||||||
var pathTable = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
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));
|
Assert.Equal("A1:D3", Helpers.GetFirstSheetDimensionRefValue(pathTable));
|
||||||
|
|
||||||
@ -1392,7 +1394,7 @@ namespace MiniExcelLibs.Tests
|
|||||||
{
|
{
|
||||||
table.Columns.Add("Column1", typeof(string));
|
table.Columns.Add("Column1", typeof(string));
|
||||||
table.Columns.Add("Column2", typeof(int));
|
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.Columns.Add("Column4", typeof(DateOnly));
|
||||||
table.Rows.Add("MiniExcel", 1, dateTime, onlyDate);
|
table.Rows.Add("MiniExcel", 1, dateTime, onlyDate);
|
||||||
table.Rows.Add("Github", 2, dateTime, onlyDate);
|
table.Rows.Add("Github", 2, dateTime, onlyDate);
|
||||||
|
Loading…
Reference in New Issue
Block a user