Giter Site home page Giter Site logo

sveinungf / spreadcheetah Goto Github PK

View Code? Open in Web Editor NEW
267.0 5.0 16.0 1.31 MB

SpreadCheetah is a high-performance .NET library for generating spreadsheet (Microsoft Excel XLSX) files.

License: MIT License

C# 100.00%
dotnet excel xlsx spreadsheet csharp-sourcegenerator nativeaot performance csharp

spreadcheetah's Introduction

SpreadCheetah

Nuget GitHub Workflow Status (with event) Codecov

SpreadCheetah is a high-performance .NET library for generating spreadsheet (Microsoft Excel XLSX) files.

Features

  • Performance (see benchmarks below)
  • Low memory allocation (see benchmarks below)
  • Async APIs
  • No dependency to Microsoft Excel
  • Targeting .NET Standard 2.0 for .NET Framework and earlier versions of .NET Core
  • Targeting .NET 6 and newer for more optimizations
  • Trimmable and native AOT compatible

SpreadCheetah is designed to create spreadsheet files in a forward-only manner. That means worksheets from left to right, rows from top to bottom, and row cells from left to right. This allows for creating spreadsheet files in a streaming manner, while also keeping a low memory footprint.

Most basic spreadsheet functionality is supported, such as cells with different data types, basic styling, and formulas. More advanced functionality will be added in future releases. See the list of currently supported spreadsheet functionality in the wiki.

See Releases for release notes.

How to install

SpreadCheetah is available as a package on nuget.org. The NuGet package targets .NET Standard 2.0 as well as newer versions of .NET. The .NET Standard 2.0 version is intended for backwards compatibility (.NET Framework and earlier versions of .NET Core). More optimizations are enabled when targeting newer versions of .NET.

Basic usage

using (var spreadsheet = await Spreadsheet.CreateNewAsync(stream))
{
    // A spreadsheet must contain at least one worksheet.
    await spreadsheet.StartWorksheetAsync("Sheet 1");

    // Cells are inserted row by row.
    var row = new List<Cell>();
    row.Add(new Cell("Answer to the ultimate question:"));
    row.Add(new Cell(42));

    // Rows are inserted from top to bottom.
    await spreadsheet.AddRowAsync(row);

    // Remember to call Finish before disposing.
    // This is important to properly finalize the XLSX file.
    await spreadsheet.FinishAsync();
}

Other examples

Using the Source Generator

Source Generators is a newly released feature in the C# compiler. SpreadCheetah includes a source generator that makes it easier to create rows from objects. It is used in a similar way to the System.Text.Json source generator:

namespace MyNamespace;

// A plain old C# class which we want to add as a row in a worksheet.
// The source generator will pick the properties with public getters.
// The order of the properties will decide the order of the cells.
public class MyObject
{
    public string Question { get; set; }
    public int Answer { get; set; }
}

The source generator will be instructed to generate code by defining a partial class like this:

using SpreadCheetah.SourceGeneration;

namespace MyNamespace;

[WorksheetRow(typeof(MyObject))]
public partial class MyObjectRowContext : WorksheetRowContext;

During build, the type will be analyzed and an implementation of the context class will be created. We can then create a row from an object by calling AddAsRowAsync with the object and the context type as parameters:

await using var spreadsheet = await Spreadsheet.CreateNewAsync(stream);
await spreadsheet.StartWorksheetAsync("Sheet 1");

var myObj = new MyObject
{
    Question = "How many Rings of Power were there?",
    Answer = 20
};

await spreadsheet.AddAsRowAsync(myObj, MyObjectRowContext.Default.MyObject);

await spreadsheet.FinishAsync();

Here is a peek at part of the code that was generated for this example. As you can see, the generated code also takes advantage of using a pooled array to avoid memory allocations:

// <auto-generated />
private static async ValueTask AddAsRowInternalAsync(Spreadsheet spreadsheet, MyObject obj, CancellationToken token)
{
    var cells = ArrayPool<DataCell>.Shared.Rent(2);
    try
    {
        cells[0] = new DataCell(obj.Question);
        cells[1] = new DataCell(obj.Answer);
        await spreadsheet.AddRowAsync(cells.AsMemory(0, 2), token).ConfigureAwait(false);
    }
    finally
    {
        ArrayPool<DataCell>.Shared.Return(cells, true);
    }
}

The source generator can generate rows from classes, records, and structs. It can be used in all supported .NET versions, including .NET Framework, however the C# version must be 8.0 or greater. More features of the source generator can be seen in the sample project.

Benchmarks

The benchmark results here have been collected using BenchmarkDotNet with the following system configuration:

BenchmarkDotNet v0.13.11, Windows 10 (10.0.19045.3803/22H2/2022Update)
Intel Core i5-8600K CPU 3.60GHz (Coffee Lake), 1 CPU, 6 logical and 6 physical cores
.NET SDK 8.0.100
  [Host]             : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2
  .NET 6.0           : .NET 6.0.25 (6.0.2523.51912), X64 RyuJIT AVX2
  .NET 8.0           : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2
  .NET Framework 4.8 : .NET Framework 4.8.1 (4.8.9181.0), X64 RyuJIT VectorSize=256

InvocationCount=1  UnrollFactor=1  

These libraries have been used in the comparison benchmarks:

Library Version
SpreadCheetah 1.12.0
Open XML SDK 2.20.0
ClosedXML 0.102.1
EPPlusFree 4.5.3.8

Disclaimer: The libraries have different feature sets compared to each other. SpreadCheetah can only create spreadsheets, while the other libraries used in this comparison can also open spreadsheets. SpreadCheetah is also a newer library and has been designed from the ground up to utilize many of the newer performance related features in .NET. The other libraries have longer history and need to take backwards compatibility into account. Keep this in mind when evaluating the results.

The code executed in the benchmark creates a worksheet of 20 000 rows and 10 columns filled with string values. Some of these libraries have multiple ways of achieving the same result, but to make this a fair comparison the idea is to use the most efficient approach for each library. The code is available in the Benchmark project.

.NET 8

Library Mean Allocated
SpreadCheetah 23.07 ms 6.44 KB
Open XML (SAX approach) 184.94 ms 66 041.63 KB
EPPlusFree 370.07 ms 195 610.91 KB
Open XML (DOM approach) 700.73 ms 182 916.73 KB
ClosedXML 754.83 ms 529 203.20 KB

.NET 6

Library Mean Allocated
SpreadCheetah 25.58 ms 6.63 KB
Open XML (SAX approach) 237.28 ms 66 055.02 KB
EPPlusFree 408.78 ms 195 791.84 KB
Open XML (DOM approach) 802.89 ms 182 926.09 KB
ClosedXML 891.17 ms 529 852.29 KB

.NET Framework 4.8

Library Mean Allocated
SpreadCheetah 65.54 ms 152.23 KB
Open XML (SAX approach) 402.34 ms 43 317.24 KB
EPPlusFree 621.00 ms 286 145.93 KB
Open XML (DOM approach) 1,051.95 ms 161 059.22 KB
ClosedXML 1,310.59 ms 509 205.80 KB

spreadcheetah's People

Contributors

bredstik avatar michael-derubertis avatar misiu avatar sveinungf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

spreadcheetah's Issues

Auto Size

Hi again! Thank you for the alignment.
I didn't find auto size on documentation related with columns.

Worksheet global styles & row styles

Hello! First of all, thank you very much for such a wonderful library. I really appreciate your work.
Maybe I didn't look well, but I didn't find a way to set global styles for the entire worksheet or for an entire row.

Use case:
I have the same font and font size for the entire worksheet. In addition some rows are bold. Specifying styles only at the cell level results in duplicate styles.

author support for comments

Currently it looks like the author of a comment is hard-coded to 0, would it be possible to add support for adding authors / setting them against comments?

Corrupted .xlsx file when using a MemoryStream

Hi, first of all thank you for your library!
Incredible performances!!

I'm working on a migration from ClosedXML to spreadcheetah integration for .xlsx export (too much memory consumption with ClosedXML).

But, I'm facing a problem. I successfully generate file but when I open it, I get an error prompt

image

EN translation: "Sorry ... we found a problem in the content of "export.xlsx", but we can try to recover the maximum content. If the source of this workbook is reliable, click yes.".

After clicking "yes", I get all my rows (no data loss).
I got this error with an empty file too.

Here my implementation:

    public async Task<byte[]> Execute(IEnumerable<PocDto> records)
    {
        await using MemoryStream memoryStream = new MemoryStream();
        await using Spreadsheet spreadsheet = await Spreadsheet.CreateNewAsync(memoryStream);

        await spreadsheet.StartWorksheetAsync("export");

        foreach (PocDto record in records)
        {
            await spreadsheet.AddAsRowAsync(record, PocDtoRowContext.Default.PocDto);
        }

        await spreadsheet.FinishAsync();

        byte[] bytes = new byte[(int)memoryStream.Length];
        memoryStream.Seek(0, SeekOrigin.Begin);
        memoryStream.Read(bytes, 0, (int)memoryStream.Length);

        return bytes;
    }

Called from a HTTP GET endpoint

    public async Task<FileContentResult> Export(some_inputs)
    {
        IEnumerable<PocDto> exportableDtos = ....;

        byte[] excelAsBytesArray = await _excelBuilder.Execute(exportableDtos);
        return File(excelAsBytesArray, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileDownloadName: $"export_{DateTime.Now:yyyyMMdd_hhmmssfff}.xlsx");
    }

After several hours, I try with a FileStream, I get a correct file, so it seems due to the usage of a MemoryStream.

Unfortunately, I working on docker image and usage of a FileStream is not an option.

Thanks in advance if you can help me!
Kind regards

Rémi.

Source generator - Cell value length limit

Add option to limit the length of a cell values when using the source generator. For example by using an attribute:

public class MyObject
{
    [CellValueTruncate(30)]
    public string Property { get; set; }
}

Source generator - Reference named styles

Background and motivation

Right now there is no way to use any styling with the source generator. Enabling styling by only using attributes (for example as suggested in #31 and #43) is an approach that would be easy to use, but requires a lot of work (and potentially many attributes) before all parts of styling would be supported.

If there would be a way to first add named styles to a spreadsheet, then these could be referenced with attributes on properties. This would be a way to have all supported forms of styling with the source generator.

API proposal

namespace SpreadCheetah;

public sealed class Spreadsheet
{
    public StyleId AddNamedStyle(string name, Style style);
}
namespace SpreadCheetah.SourceGeneration;

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class CellNamedStyleAttribute(string name) : Attribute;

API usage

public class Person
{
    [CellNamedStyle("My FirstName style")]
    public string FirstName { get; set; }
}

[WorksheetRow(typeof(Person))]
public partial class PersonRowContext : WorksheetRowContext;
await using var spreadsheet = await Spreadsheet.CreateNewAsync(stream);
await spreadsheet.StartWorksheetAsync("Sheet 1");

var style = new Style();
style.Font.Bold = true;

spreadsheet.AddNamedStyle("My FirstName style", style);

var person = new Person { FirstName = "Ola" };
await spreadsheet.AddAsRowAsync(person, PersonRowContext.Default.Person);

DateTime cell

Hi,
Do you have any example for a DateTime cell with format ?

Freeze and Filter First Row helper

It looks like you support filtering a row, although don't have a specific way to say "first row up to the last populated column".
Using your source generator object model, I'd want the range to be the first index and last index written to the excel document.

I'd similarly want to write a whole collection to the spreadsheet.

Here are some possible interfaces:

void SetAutoFilter(string sheetName, CellRelativeReferenceRange range);

// In the general case, this would require a way to get the Max Display Range to compute the start cell and end cell.
void FreezeAndAutoFilterFirstRow(string sheetName);

Additionally, freeze panes would be a bonus although I honestly rarely use these:

/// <summary>Freezes panes at the specified cell in the worksheet.</summary>
/// <param name="row">Row index.</param>
/// <param name="column">Column index.</param>
/// <param name="freezedRows">Number of visible rows in top pane, no more than row index.</param>
/// <param name="freezedColumns">Number of visible columns in left pane, no more than column index.</param>
/// <remarks>
///   <p>Row index and column index cannot all be zero. Number of rows and number of columns
///       also cannot all be zero.</p>
///   <p>The first two parameters specify the froze position and the last two parameters specify the area frozen on the left top pane.</p>
/// </remarks>
void FreezePanes(int row, int column, int freezedRows, int freezedColumns);

File is corrupted when downloading from Blazor WASM

Hi,

I'm trying to create a method for allowing the downloading of an Excel file from a Blazor WASM app.

private async Task ExportToExcel()
{
    var fileName = @"tessssst.xlsx";

    using var fileStream = new MemoryStream();

    using (var spreadsheet = await Spreadsheet.CreateNewAsync(fileStream))
    {
        // A spreadsheet must contain at least one worksheet.
        await spreadsheet.StartWorksheetAsync("Sheet 1");

        // Cells are inserted row by row.
        var row = new List<Cell>
        {
            new("Answer to the ultimate question:"),
            new(42)
        };

        // Rows are inserted from top to bottom.
        await spreadsheet.AddRowAsync(row);

        // Remember to call Finish before disposing.
        // This is important to properly finalize the XLSX file.
        await spreadsheet.FinishAsync();
    }

    using var streamRef = new DotNetStreamReference(stream: fileStream);
    await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}

the method calls a JS included in the index.html file:

<script>
    window.downloadFileFromStream = async (fileName, contentStreamReference) => {
        const arrayBuffer = await contentStreamReference.arrayBuffer();
        const blob = new Blob([arrayBuffer]);
        const url = URL.createObjectURL(blob);
        const anchorElement = document.createElement('a');
        anchorElement.href = url;
        anchorElement.download = fileName ?? '';
        anchorElement.click();
        anchorElement.remove();
        URL.revokeObjectURL(url);
    }
</script>

Whilst the file is indeed created and downloaded to the downloads folder of my PC, I can see that the size of the file is 0 bytes.

IS this a bug, or am I missing something here?

Merge cells

I didn't find anything to merge cells, can you help me?
Thank you!

Source generator - Fixed column widths

Background and motivation

Fixed column widths are now set on WorksheetOptions when creating a worksheet. There is a desire to be able to set these with attributes instead when using the source generator. A fairly straight forward way to then have them applied to a worksheet would be to pass the source generator metadata type to StartWorksheetAsync.

API proposal

namespace SpreadCheetah.SourceGeneration;

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class ColumnWidthAttribute(double width) : Attribute;
namespace SpreadCheetah;

public sealed class Spreadsheet
{
    public ValueTask StartWorksheetAsync<T>(string name, WorksheetRowTypeInfo<T> typeInfo, CancellationToken token = default);
}

API usage

public class Person
{
    [ColumnWidth(20)]
    public string FirstName { get; set; }
}

[WorksheetRow(typeof(Person))]
public partial class PersonRowContext : WorksheetRowContext;
await using var spreadsheet = await Spreadsheet.CreateNewAsync(stream);
await spreadsheet.StartWorksheetAsync("Sheet 1", PersonRowContext.Default.Person);

Source generator - Cell fill color

Is there a way to use cell styles attributes with source generator?
For example, I want to highlight specific property in my class:

public class MyObject
{
        [HighlightExcelCell('some color')]
        public string Property{ get; set; }
}

ILT0038 compilation error on UWP with .NET Native

After updating the packager from 1.14.0 to 1.15.0, I'm unable to compile for UWP in release mode (using .NET Native).

I get the following error:

ILT0038: 'SpreadCheetah.CellValues.CellValue' is a value type with a default constructor. Value types with default constructors are not currently supported. Consider using an explicit initialization function instead.

I haven't found a workaround yet to be able to use this package. Is this something that can be fixed, or is there a workaround to get the build running?

Source generator - Number format

First of all, thank you for your super fast library :)

Could you add an option to specify the style of the column when using the source generator ?

This will be useful to customize datetime and number formatting on a column basis. Something like a ColumnFormattingAttribute class which takes a StandardNumberFormat for simplicity.

public class Person
{
    [ColumnFormatting(Standard = StandardNumberFormat.NoDecimalPlaces)]
    public int Age { get; set; }

    [ColumnFormatting(Standard = StandardNumberFormat.ShortDate)]
    public DateTime ModifiedAt { get; set; }
}

[WorksheetRow(typeof(Person))]
public partial class PersonRowContext : WorksheetRowContext;

Thank you.

Spreadsheets are empty when opening in "Spreadsheet compare" Office tool

Hello! First of all, thank you for the amazing tooling, metrics are really great and writes are so performant! I'm able to generate large xlsx files using .NET.

However, I have faced the issue when trying to compare the file generated with SpreadCheetah, with other xlsx files using the Spreadsheet Compare 2016 tool (part of Office). The file generated using SpreadCheetah is treated as empty for some reason by this tool, so I can't compare it with others. At the same time, the file in Excel looks good and has the data. I had no similar issue when opening files created using NPOI package.

So, is it possible to make the SpreadCheetah-generated xlsx files compatible with Spreadsheet Compare?
Could you please let me know if you can plan it, so that I can realize whether I can fully migrate to SpreadCheetah?

This is how the issue looks like in Spreadsheet Compare (left file that looks empty - SpreadCheetah, right file - created in Excel):
image

This is how the file looks like in Excel - it's not empty:
image

Minimal code:

using var tempStream = new MemoryStream();
await using var spreadsheet = await Spreadsheet.CreateNewAsync(tempStream, null, cancellationToken);
await spreadsheet.StartWorksheetAsync("Report", null, cancellationToken);

var columnNames = new List<string> { "column1", "column2" };
var values = new List<string> { "value1", "value2" };

var headerRow = new List<Cell>();

foreach (var columnName in columnNames)
{
     headerRow.Add(new Cell(columnName));
}

await spreadsheet.AddRowAsync(headerRow, cancellationToken);

var valuesRow = new List<Cell>();
foreach (var value in values)
{
    valuesRow.Add(new Cell(value));
}
await spreadsheet.AddRowAsync(valuesRow, cancellationToken);

await spreadsheet.FinishAsync(cancellationToken);

Environment:
Spreadcheetah 1.9.0
.NET 6

Add support for AutoFilter

Please add support for AutoFilter for Worksheets.

In the sheet XML, there is a property name autoFilter that should be placed after <sheetData/>.

Based on preliminary testing, it should contain two attributes:

  • ref: The range of data (will be the entire range for my purposes, but will try to make it configurable)
  • xr:uid: Unknown. Will need to look into the OpenXML specs to see if it's listed.

<autoFilter ref="A1:P23171" xr:uid="{68C1B19E-3898-438A-AF56-CC838EB61945}"/>

I will create a pull request once I have something worth testing.

Add columns title and order customisation attributes to source generator

Could you add an option to specify the title of the column and it's order with the attributes?

This would be pretty useful when a property name doesn't represent what is expected in the column header (e.g. multiple words or non-latin name). The columns order attribute would allow storing the row model properties in an arbitrary order (e.g. sorted alphabetically).

I'd suggest using the DataMemberAttribute to specify an order and the DescriptionAttribute to specify a custom name.

[DataMember(Order = 1)]
[Description("Some value")]
public string SomeValue { get; set; }

DateTime is not supported in source generator

First of all, I'd like to say, that I'm shocked (in a positive way) by how fast this library is and how little RAM is needed to generate the file.
I have a simple POC app that is used to export data from the database. It is creating a single Excel file with around 100 worksheets, each having around 600,000 rows with only two columns.
I was using Syncfusion XlsIO before and the speed was terrible (export took around 20 minutes), worst of all it needed around 24 GB of RAM!
Now the same test result set is exported in 13 seconds and it requires only 18 MB of RAM.
This is insane!

I've tried using batch insert using source generator and AddRangeAsRowsAsync, but I'm getting this waring:

The type 'DataRecord' has a property of type 'DateTime' which is not supported as a cell value. The property will be ignored when creating the row.

Here is my class:

public class DataRecord
{
    public DataRecord(DateTime dateTime, int value)
    {
        Date = dateTime;
        Value = value;
    }

    public int Value { get; set; }

    public DateTime Date { get; set; }
}

[WorksheetRow(typeof(DataRecord))]
public partial class DataRecordContext : WorksheetRowContext
{
}

We can create a DataCell with DateTime, so I think it should be supported in source generator.

The below code works fine when I'm adding records one by one (without source generator)

  private static async Task ExportWithSpreadCheetah()
  {
      var stopwatch = new Stopwatch();
      stopwatch.Start();

      await using (var stream = File.Create("spreadcheetah.xlsx"))
      {
          var options = new SpreadCheetahOptions
          {
              CompressionLevel = SpreadCheetahCompressionLevel.Optimal
          };
          await using var spreadsheet = await Spreadsheet.CreateNewAsync(stream, options);

          var headerStyle = new Style();
          headerStyle.Font.Bold = true;
          var headerStyleId = spreadsheet.AddStyle(headerStyle);

          for (var i = 0; i < NUMBER_OF_WORKSHEETS; i++)
          {
              await spreadsheet.StartWorksheetAsync($"Sheet {i}");

              var header1 = new[]
              {
                  new StyledCell($"Sample description {i}", headerStyleId),
              };
              var header2 = new[]
              {
                  new StyledCell("Data", headerStyleId),
                  new StyledCell("Value", headerStyleId)
              };

              await spreadsheet.AddRowAsync(header1);
              spreadsheet.MergeCells("A1:B1");
              await spreadsheet.AddRowAsync(header2);

              //this simulates loading data from the database
              for (var j = 0; j < NUMBER_OF_ROWS; j++)
              {
                  var dateTime = new DateTime(2023, 1, 1).AddSeconds(j);

                  var dataRow = new[]
                  {
                      new DataCell(dateTime),
                      new DataCell(j)
                  };

                  await spreadsheet.AddRowAsync(dataRow);
              }

              Debug.WriteLine($"Data saved to worksheet ({i + 1}/{NUMBER_OF_WORKSHEETS})");
          }

          await spreadsheet.FinishAsync();

          stopwatch.Stop();
          Debug.WriteLine($"Saving data to file took {stopwatch.ElapsedMilliseconds} ms");
      }

      Process.Start(new ProcessStartInfo("spreadcheetah.xlsx") { UseShellExecute = true });
  }

Cell format: Align

This is an excellent library to generate spreadsheets! Thank you.
Is there a way to format a cell with a simple text alignment?
Horizontal (left, center, right) and/or Vertical alignment (top, middle, bottom).

Add hyperlink support

Hi,

First of all thanks for this project. I like the API simplicity for creating the spreasheet files.

I need to define hyperlinks, for example:

new HyperlinkCell("https://github.com/sveinungf/spreadcheetah/", "spreadcheetah's Repository");

where we have the URI and the display text.

Currently, the URI is displayed as plain text, wihtout hyperlink formatting.

image

I don't know if you have something that covers that scenario already, but I couldn't find it.

Thanks!

Source generator - Column headers from Resource files

Background and motivation

Allow referencing Resource files (.resx) when using ColumnHeaderAttribute. This is useful in apps that support localization.

API proposal

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class ColumnHeaderAttribute : Attribute
{
    public ColumnHeaderAttribute(string name)
    {
    }

+   public ColumnHeaderAttribute(Type type, string propertyName)
+   {
+   }
}

API usage

public class Person
{
    [ColumnHeader(typeof(MyResources), nameof(MyResources.FirstName_Header))]
    public string FirstName { get; set; }
}

Request: Would it be possible to sign the assembly with a strong name?

In order to reference this assembly from another assembly which is signed, a strongly-named assembly is required. Could you add strong-name signing to this assembly? https://learn.microsoft.com/en-us/dotnet/standard/assembly/sign-strong-name

All it should take is generating a keyfile with sn.exe: https://learn.microsoft.com/en-us/dotnet/standard/assembly/create-public-private-key-pair and then checking the box in the project properties. I can provide a PR for this if you like (unless you want to keep the keyfile private so no fork can identify as being the same assembly).

image support

I couldn't find anything about adding an image. How can I insert an image, especially an embedded one?

Source generator - use fields of base class

Currently, the source code generator generates properties only for the class that is specified in the worksheet row attribute but the properties of the base class are ignored.

I can try to make a PR if you want

Why are all types in the CellReferences namespace internal?

I am guessing the reason has something to do with code generation, but I'm sure you have a much deeper understanding of your architecture decisions than I do.

My initial thought is I'd like to be able to work with cell references directly, especially cell ranges, and to have convenience properties on ranges like FirstRow, FirstColumn, LastRow, LastColumn, But, if features like #55 are implemented using internal tools, then this is probably not needed for me/by me. I'm just used to using commercial libraries where I can easily do these things.

Conditional formatting

I'd like to ask for adding support for conditional formatting.
Use case:
I'm generating a report that contains a couple of columns, in the last columns I need to calculate the average from previous ones. If it is less than 1 I'd like to set the background to red, if it is more than 4.9 I want the background to be green.
I know I can calculate the value per row in my app, then put the value as the average column and apply styleId. Still, ideally, I'd like to use a formula to calculate the value (this can be done right now) and apply a conditional style to that cell, so when someone updates the values in the generated Excel file the average and the color will update.

Ref: https://stackoverflow.com/a/25724262/965722

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.