mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-11-29 18:38:08 +08:00
Add freeze panes (#626)
* add template formula example images * add template formula example to readme * add template formula example to readme * get basics working * add config option * add WritePanes method, remove FreezeTopRow, add FreezeRowCount and FreezeColumnCount options, add unit test * add xml methods to WorksheetXml * remove unused namespaces * revert disable file delete * add freeze panes feature to table and idatareader
This commit is contained in:
parent
273fe9756f
commit
1cd491cc13
@ -13,9 +13,34 @@ namespace MiniExcelLibs.OpenXml.Constants
|
||||
internal static string Dimension(string dimensionRef)
|
||||
=> $"{StartDimension}{dimensionRef}\"/>";
|
||||
|
||||
internal const string StartSheetViews = "<x:sheetViews>";
|
||||
internal const string EndSheetViews = "</x:sheetViews>";
|
||||
|
||||
internal static string StartSheetView( int tabSelected=1, int workbookViewId=0 )
|
||||
=> $"<x:sheetView tabSelected=\"{tabSelected}\" workbookViewId=\"{workbookViewId}\">";
|
||||
internal const string EndSheetView = "</x:sheetView>";
|
||||
|
||||
internal const string StartSheetData = "<x:sheetData>";
|
||||
internal const string EndSheetData = "</x:sheetData>";
|
||||
|
||||
internal static string StartPane( int? xSplit, int? ySplit, string topLeftCell, string activePane, string state )
|
||||
=> string.Concat(
|
||||
"<x:pane",
|
||||
xSplit.HasValue ? $" xSplit=\"{xSplit.Value}\"" : string.Empty,
|
||||
ySplit.HasValue ? $" ySplit=\"{ySplit.Value}\"" : string.Empty,
|
||||
$" topLeftCell=\"{topLeftCell}\"",
|
||||
$" activePane=\"{activePane}\"",
|
||||
$" state=\"{state}\"",
|
||||
"/>");
|
||||
|
||||
internal static string PaneSelection( string pane, string activeCell, string sqref)
|
||||
=> string.Concat(
|
||||
$"<x:selection",
|
||||
$" pane=\"{pane}\"",
|
||||
string.IsNullOrWhiteSpace(activeCell) ? string.Empty : $" activeCell=\"{activeCell}\"",
|
||||
string.IsNullOrWhiteSpace(sqref) ? string.Empty : $" sqref=\"{sqref}\"",
|
||||
"/>");
|
||||
|
||||
internal static string StartRow(int rowIndex)
|
||||
=> $"<x:row r=\"{rowIndex}\">";
|
||||
internal const string EndRow = "</x:row>";
|
||||
|
@ -1,5 +1,4 @@
|
||||
using MiniExcelLibs.Attributes;
|
||||
using MiniExcelLibs.OpenXml.Constants;
|
||||
using MiniExcelLibs.OpenXml.Constants;
|
||||
using MiniExcelLibs.OpenXml.Models;
|
||||
using MiniExcelLibs.Utils;
|
||||
using MiniExcelLibs.Zip;
|
||||
@ -7,12 +6,10 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static MiniExcelLibs.Utils.ImageHelper;
|
||||
|
||||
namespace MiniExcelLibs.OpenXml
|
||||
{
|
||||
@ -136,6 +133,9 @@ namespace MiniExcelLibs.OpenXml
|
||||
}
|
||||
maxColumnIndex = props.Count;
|
||||
|
||||
//sheet view
|
||||
WriteSheetViews(writer);
|
||||
|
||||
WriteColumnsWidths(writer, props);
|
||||
|
||||
writer.Write(WorksheetXml.StartSheetData);
|
||||
@ -260,6 +260,9 @@ namespace MiniExcelLibs.OpenXml
|
||||
writer.Write(WorksheetXml.Dimension(GetDimensionRef(maxRowIndex, maxColumnIndex)));
|
||||
}
|
||||
|
||||
//sheet view
|
||||
WriteSheetViews(writer);
|
||||
|
||||
//cols:width
|
||||
WriteColumnsWidths(writer, props);
|
||||
|
||||
@ -331,6 +334,9 @@ namespace MiniExcelLibs.OpenXml
|
||||
var prop = GetColumnInfosFromDynamicConfiguration(columnName);
|
||||
props.Add(prop);
|
||||
}
|
||||
|
||||
//sheet view
|
||||
WriteSheetViews(writer);
|
||||
|
||||
WriteColumnsWidths(writer, props);
|
||||
|
||||
@ -389,6 +395,91 @@ namespace MiniExcelLibs.OpenXml
|
||||
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;
|
||||
|
@ -8,6 +8,8 @@ namespace MiniExcelLibs.OpenXml
|
||||
public bool FillMergedCells { get; set; }
|
||||
public TableStyles TableStyles { get; set; } = TableStyles.Default;
|
||||
public bool AutoFilter { get; set; } = true;
|
||||
public int FreezeRowCount { get; set; } = 1;
|
||||
public int FreezeColumnCount { get; set; } = 0;
|
||||
public bool EnableConvertByteArray { get; set; } = true;
|
||||
public bool IgnoreTemplateParameterMissing { get; set; } = true;
|
||||
public bool EnableWriteNullValueCell { get; set; } = true;
|
||||
|
@ -56,10 +56,10 @@ namespace MiniExcelLibs.Tests
|
||||
string path = GetTempXlsxPath();
|
||||
char[] chars = new char[] {'\u0000','\u0001','\u0002','\u0003','\u0004','\u0005','\u0006','\u0007','\u0008',
|
||||
'\u0009', //<HT>
|
||||
'\u000A', //<LF>
|
||||
'\u000B','\u000C',
|
||||
'\u000A', //<LF>
|
||||
'\u000B','\u000C',
|
||||
'\u000D', //<CR>
|
||||
'\u000E','\u000F','\u0010','\u0011','\u0012','\u0013','\u0014','\u0015','\u0016',
|
||||
'\u000E','\u000F','\u0010','\u0011','\u0012','\u0013','\u0014','\u0015','\u0016',
|
||||
'\u0017','\u0018','\u0019','\u001A','\u001B','\u001C','\u001D','\u001E','\u001F','\u007F'
|
||||
};
|
||||
var input = chars.Select(s => new { Test = s.ToString() });
|
||||
@ -823,6 +823,67 @@ namespace MiniExcelLibs.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact()]
|
||||
public void SaveAsFrozenRowsAndColumnsTest() {
|
||||
|
||||
var config = new OpenXmlConfiguration
|
||||
{
|
||||
FreezeRowCount = 1,
|
||||
FreezeColumnCount = 2
|
||||
};
|
||||
|
||||
{
|
||||
// Test enumerable
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||
MiniExcel.SaveAs(
|
||||
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");
|
||||
MiniExcel.SaveAs(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");
|
||||
|
||||
MiniExcel.SaveAs(pathReader, reader, configuration: config);
|
||||
Assert.Equal("A1:D3", Helpers.GetFirstSheetDimensionRefValue(pathTable));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Fact()]
|
||||
public void SaveAsByDapperRows()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user