FluentSpreadsheets.ClosedXML
1.3.0
See the version list below for details.
dotnet add package FluentSpreadsheets.ClosedXML --version 1.3.0
NuGet\Install-Package FluentSpreadsheets.ClosedXML -Version 1.3.0
<PackageReference Include="FluentSpreadsheets.ClosedXML" Version="1.3.0" />
paket add FluentSpreadsheets.ClosedXML --version 1.3.0
#r "nuget: FluentSpreadsheets.ClosedXML, 1.3.0"
// Install FluentSpreadsheets.ClosedXML as a Cake Addin #addin nuget:?package=FluentSpreadsheets.ClosedXML&version=1.3.0 // Install FluentSpreadsheets.ClosedXML as a Cake Tool #tool nuget:?package=FluentSpreadsheets.ClosedXML&version=1.3.0
FluentSpreadsheets
FluentSpreadsheets
FluentSpreadsheets.ClosedXML
FluentSpreadsheets.GoogleSheets
Overview
FluentSpreadsheets library consists of two APIs:
- Component API
An API that provides a set ofcomponents
, that can be used for building static UI with sheet cells as building blocks, as well as base logic for drawing defined component composition on the sheet. - Table API
An API that provides a set of abstractions to definetables
by usingrows
built fromcomponents
andcomponent sources
.
Examples
Component API
The base unit of component API is IComponent
interface, it provides a basic interface to interact with all components.
public interface IComponent
{
Size Size { get; }
void Accept(IComponentVisitor visitor);
}
There are many derived interfaces from IComponent
used to reflect on component type in IComponentVisitor
.
All component implementations are internal, so to create an instance of a component you need to use a static
class ComponentFactory
.
Hint
You can import static members of
ComponentFactory
for cleaner code.using static FluentSpreadsheets.ComponentFactory;
Components
Use .Label
to create a label component. You can pass a string
to it, or use a generic overload which will
call ToString
on the passed object (IFormattable
overload supported).
Label("Hello, World!");
Label(2.2, CultureInfo.InvariantCulture);
Containers
Use .VStack
& .HStack
to stack components vertically or horizontally, they will auto scale child components' width
and height respectively.
VStack
(
HStack
(
Label("Hello"),
Label(",")
),
Label("Stacks!")
)
The result will be something like this:
Stacks will automatically scale their children so they all will have an equal width/height and fill a rectangle.
Styles
Use extension methods to style components.
Styles are cascading! It means that styles applied to container will be inherited by its children (and overriden, if
needed). \
Cascading behaviour does not apply to styling of single component, if you will apply style A on a component, then style B, the component will have a style equal to style B applied to style A.
VStack
(
HStack
(
Label("Hello").WithContentAlignment(HorizontalAlignment.Trailing),
Label(",")
),
Label("Styles!").WithContentAlignment(HorizontalAlignment.Center, VerticalAlignment.Top)
).WithTrailingBorder(BorderType.Thin, Color.Black).WithBottomBorder(BorderType.Thin, Color.Black)
Components are immutable, when you apply a style to a component, it will return a new component with the style applied, the object you called a method on will not be changed.
The result will be something like this:
Resizing
Size values are accepted as relative multipliers to default platform's sizes (column width/row height). \
Output
Code above will only produce component composition stored as objects in memory. To render it on the sheet,
you need to use IComponentRenderer<T>
.
Now supported:
Excel output via "ClosedXML" library. (You will need to reference a FluentSpreadsheets.ClosedXML
NuGet package)
var workbook = new XLWorkbook();
var worksheet = workbook.AddWorksheet("Sample");
var helloComponent =
VStack
(
HStack
(
Label("Hello")
.WithContentAlignment(HorizontalAlignment.Trailing)
.WithTrailingBorder(BorderType.Thin, Color.Black),
Label(",")
),
Label("Styles!")
.WithContentAlignment(HorizontalAlignment.Center, VerticalAlignment.Top)
.WithTopBorder(BorderType.Thin, Color.Black)
.WithRowHeight(1.7)
).WithBottomBorder(BorderType.Thin, Color.Black).WithTrailingBorder(BorderType.Thin, Color.Black);
var renderer = new ClosedXmlComponentRenderer();
var renderCommand = new ClosedXmlRenderCommand(worksheet, helloComponent);
await renderer.RenderAsync(renderCommand);
workbook.SaveAs("sample.xlsx");
Google Sheets output via "Google Sheets API v4" library. (You will need to referencea FluentSpreadsheets.GoogleSheets
NuGet package)
var credential = GoogleCredential.FromFile("credentials.json");
var initializer = new BaseClientService.Initializer
{
HttpClientInitializer = credential
};
var service = new SheetsService(initializer);
var renderer = new GoogleSheetComponentRenderer(service);
var helloComponent =
VStack
(
HStack
(
Label("Hello")
.WithContentAlignment(HorizontalAlignment.Trailing)
.WithTrailingBorder(BorderType.Thin, Color.Black),
Label(",")
),
Label("Styles!")
.WithContentAlignment(HorizontalAlignment.Center, VerticalAlignment.Top)
.WithTopBorder(BorderType.Thin, Color.Black)
.WithRowHeight(1.7)
).WithBottomBorder(BorderType.Thin, Color.Black).WithTrailingBorder(BorderType.Thin, Color.Black);
const string spreadsheetId = "SampleSpreadsheetId";
const string title = "SampleTitle";
var renderCommandFactory = new RenderCommandFactory(service);
var renderCommand = await renderCommandFactory.CreateAsync(spreadsheetId, title, helloComponent);
await renderer.RenderAsync(renderCommand);
Table API
Table API is based on ITable<T>
interface, where T
is a type of model, that is used to render a table.
To define a table you need to create a class derived from RowTable<T>
and
implement IEnumerable<IRowComponent> RenderRows(T model)
method.
To customize rendered table override Customize
method in your table class.
public readonly record struct CartItem(string Name, decimal Price, int Quantity);
public readonly record struct CartTableModel(IReadOnlyCollection<CartItem> Items);
public class CartTable : RowTable<CartTableModel>, ITableCustomizer
{
protected override IEnumerable<IRowComponent> RenderRows(CartTableModel model)
{
yield return Row
(
Label("Product Name").WithColumnWidth(1.7),
Label("Price"),
Label("Quantity")
);
foreach (var item in model.Items)
{
yield return Row
(
Label(item.Name),
Label(item.Price, CultureInfo.InvariantCulture),
Label(item.Quantity)
);
}
}
public override IComponent Customize(IComponent component)
{
return component
.WithBottomBorder(BorderType.Thin, Color.Black)
.WithTrailingBorder(BorderType.Thin, Color.Black);
}
}
Use .Render
method on table instance to create a component from model.
var items = new CartItem[]
{
new CartItem("Water", 10, 10),
new CartItem("Bread", 20, 10),
new CartItem("Milk", 30, 10),
new CartItem("Eggs", 40, 10),
};
var model = new CartTableModel(items);
var table = new CartTable();
var tableComponent = table.Render(model);
If you want to customize already scaled component group, you can call a CustomizedWith
modifier on it.
(ex: add a common header for a header group), you can see it's usage in a
student points table example
ForEach(model.HeaderData.Labs, headerData => VStack
(
Label(headerData.Name),
HStack
(
Label("Min"),
Label("Max")
),
HStack
(
Label(headerData.MinPoints, CultureInfo.InvariantCulture),
Label(headerData.MaxPoints, CultureInfo.InvariantCulture)
)
)).CustomizedWith(x => VStack(Label("Labs"), x))
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- ClosedXML (>= 0.96.0)
- FluentSpreadsheets (>= 1.3.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.6.7 | 256 | 11/12/2023 |
1.6.6 | 155 | 11/1/2023 |
1.6.5 | 136 | 10/12/2023 |
1.6.4 | 146 | 9/27/2023 |
1.6.3 | 137 | 9/27/2023 |
1.5.1 | 122 | 9/21/2023 |
1.4.4 | 316 | 3/22/2023 |
1.4.3 | 251 | 3/22/2023 |
1.4.2 | 231 | 3/22/2023 |
1.4.1 | 229 | 3/22/2023 |
1.4.0 | 231 | 3/21/2023 |
1.3.1 | 269 | 2/20/2023 |
1.3.0 | 377 | 11/24/2022 |
1.2.4 | 405 | 9/21/2022 |
1.2.3 | 416 | 9/21/2022 |
1.2.2 | 496 | 9/18/2022 |
1.2.1 | 476 | 9/14/2022 |
1.2.0 | 443 | 9/12/2022 |
1.1.0 | 430 | 9/11/2022 |
1.0.1 | 433 | 9/4/2022 |
1.0.0 | 408 | 8/30/2022 |
0.0.3-alpha | 199 | 8/6/2022 |
0.0.2-alpha | 190 | 8/5/2022 |
0.0.1-alpha | 192 | 7/31/2022 |
Relative cell sizing