Przejdź do treści stopki
KORZYSTANIE Z IRONXL

Jak stworzyć tabele przestawne w Excel z C# używając IronXL

Programowe generowanie tabel przestawnych w programie Excel wymaga albo C# Interop wraz z zależnościami pakietu Office, albo nowoczesnej biblioteki, takiej jak IronXL, która działa niezależnie — ten samouczek przedstawia oba podejścia i pokazuje dokładnie, dłączego nowoczesna ścieżka jest lepszym wyborem.

Tworzenie raportów typu pivot w kodzie .NET po stronie serwera lub na wielu platformach zawsze było kłopotliwe. Tradycyjna metoda COM Interop wiąże użytkownika z komputerem z systemem Windows i pełną instalacją pakietu Office, powoduje wycieki pamięci w przypadku pominięcia choćby jednego wywołania czyszczenia COM i zawodzi w momencie próby wdrożenia na systemie Linux lub w kontenerze Docker. Nowoczesna alternatywa — pisanie logiki agregacji za pomocą IronXL i LINQ — działa wszędzie tam, gdzie działa .NET, nie wymaga licencji Office i zapewnia przejrzysty, czytelny kod.

W niniejszym przewodniku szczegółowo omówiono obie techniki. Poznasz surowe podejście Interop, zrozumiesz dokładnie, co sprawia, że jest ono kruche, a następnie zbudujesz ten sam arkusz podsumowujący w stylu pivot przy użyciu IronXL w C#. Zobaczysz również, jak używać formuł programu Excel do tworzenia na bieżąco aktualizowanych podsumowań, które działają jak prawdziwe odświeżanie tabeli przestawnej.

Czym jest tabela przestawna w programie Excel?

Tabela przestawna jest jednym z najpotężniejszych narzędzi analitycznych w oprogramowaniu do obsługi arkuszy kalkulacyjnych. Podsumowuje duże zbiory danych poprzez grupowanie wierszy, agregowanie wartości i przedstawianie wyników w układzie tabeli krzyżowej — wszystko to bez konieczności ręcznego wpisywania ani jednej formuły. Oficjalna dokumentacja Microsoftu dotycząca tabel przestawnych zawiera szczegółowy opis działania tej funkcji w programie Excel.

Tabele przestawne występują w programach Microsoft Excel, Arkusze Google, Apple Numbers i większości innych narzędzi do tworzenia arkuszy kalkulacyjnych. Podstawowa koncepcja jest zawsze taka sama: definiujesz pola wierszy, pola kolumn i pola wartości, a narzędzie tworzy dla Ciebie macierz podsumowującą. Gdy zmieniają się dane bazowe, wystarczy odświeżyć tabelę przestawną, a podsumowanie zaktualizuje się automatycznie.

W kodzie po stronie serwera w języku C# masz dwie szerokie opcje:

  • C# Interop — automatyzuje uruchomiony proces programu Excel za pośrednictwem COM w celu utworzenia prawdziwego, natywnego obiektu tabeli przestawnej w pliku XLSX
  • IronXL z agregacją LINQ — wczytuje skoroszyt do pamięci, oblicza to samo podsumowanie w zarządzanym kodzie .NET i zapisuje wynik w nowym arkuszu

Obie opcje dają użyteczny wynik. Jednak tylko jedno z nich działa niezawodnie w nowoczesnych środowiskach wdrożeniowych.

Jak utworzyć tabelę przestawną przy użyciu C# Interop?

C# Excel Interop zapewnia bezpośredni dostęp do natywnej funkcji tabel przestawnych programu Excel poprzez automatyzację COM. Tworzysz obiekt Excel.Application, otwierasz skoroszyt, definiujesz pamięć podręczną tabeli przestawnej wskazującą zakres danych, a następnie konfigurujesz pola wierszy, pola kolumn i pola danych.

Jak skonfigurować kod tabeli przestawnej Interop

using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

// Create Excel application instance
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"C:\Data\SalesData.xlsx");
Excel.Worksheet xlSheet = (Excel.Worksheet)xlWorkbook.Sheets[1];
Excel.Worksheet xlPivotSheet = (Excel.Worksheet)xlWorkbook.Sheets.Add();

// Define data range for pivot table
Excel.Range dataRange = xlSheet.UsedRange;

// Create pivot cache and pivot table
Excel.PivotCache pivotCache = xlWorkbook.PivotCaches().Create(
    Excel.XlPivotTableSourceType.xlDatabase,
    dataRange,
    Type.Missing);
Excel.PivotTable pivotTable = pivotCache.CreatePivotTable(
    xlPivotSheet.Cells[3, 1],
    "SalesPivot",
    Type.Missing,
    Type.Missing);

// Configure pivot table fields
Excel.PivotField productField = (Excel.PivotField)pivotTable.PivotFields("Product");
productField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
productField.Position = 1;

Excel.PivotField regionField = (Excel.PivotField)pivotTable.PivotFields("Region");
regionField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField;
regionField.Position = 1;

Excel.PivotField salesField = (Excel.PivotField)pivotTable.PivotFields("Sales");
pivotTable.AddDataField(salesField, "Sum of Sales", Excel.XlConsolidationFunction.xlSum);

// Save and cleanup
xlWorkbook.SaveAs(@"C:\Data\PivotReport.xlsx");
xlWorkbook.Close();
xlApp.Quit();

// Release COM objects to prevent memory leaks
Marshal.ReleaseComObject(pivotTable);
Marshal.ReleaseComObject(pivotCache);
Marshal.ReleaseComObject(xlPivotSheet);
Marshal.ReleaseComObject(xlSheet);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

// Create Excel application instance
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"C:\Data\SalesData.xlsx");
Excel.Worksheet xlSheet = (Excel.Worksheet)xlWorkbook.Sheets[1];
Excel.Worksheet xlPivotSheet = (Excel.Worksheet)xlWorkbook.Sheets.Add();

// Define data range for pivot table
Excel.Range dataRange = xlSheet.UsedRange;

// Create pivot cache and pivot table
Excel.PivotCache pivotCache = xlWorkbook.PivotCaches().Create(
    Excel.XlPivotTableSourceType.xlDatabase,
    dataRange,
    Type.Missing);
Excel.PivotTable pivotTable = pivotCache.CreatePivotTable(
    xlPivotSheet.Cells[3, 1],
    "SalesPivot",
    Type.Missing,
    Type.Missing);

// Configure pivot table fields
Excel.PivotField productField = (Excel.PivotField)pivotTable.PivotFields("Product");
productField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
productField.Position = 1;

Excel.PivotField regionField = (Excel.PivotField)pivotTable.PivotFields("Region");
regionField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField;
regionField.Position = 1;

Excel.PivotField salesField = (Excel.PivotField)pivotTable.PivotFields("Sales");
pivotTable.AddDataField(salesField, "Sum of Sales", Excel.XlConsolidationFunction.xlSum);

// Save and cleanup
xlWorkbook.SaveAs(@"C:\Data\PivotReport.xlsx");
xlWorkbook.Close();
xlApp.Quit();

// Release COM objects to prevent memory leaks
Marshal.ReleaseComObject(pivotTable);
Marshal.ReleaseComObject(pivotCache);
Marshal.ReleaseComObject(xlPivotSheet);
Marshal.ReleaseComObject(xlSheet);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Runtime.InteropServices

' Create Excel application instance
Dim xlApp As New Excel.Application()
Dim xlWorkbook As Excel.Workbook = xlApp.Workbooks.Open("C:\Data\SalesData.xlsx")
Dim xlSheet As Excel.Worksheet = CType(xlWorkbook.Sheets(1), Excel.Worksheet)
Dim xlPivotSheet As Excel.Worksheet = CType(xlWorkbook.Sheets.Add(), Excel.Worksheet)

' Define data range for pivot table
Dim dataRange As Excel.Range = xlSheet.UsedRange

' Create pivot cache and pivot table
Dim pivotCache As Excel.PivotCache = xlWorkbook.PivotCaches().Create(Excel.XlPivotTableSourceType.xlDatabase, dataRange, Type.Missing)
Dim pivotTable As Excel.PivotTable = pivotCache.CreatePivotTable(xlPivotSheet.Cells(3, 1), "SalesPivot", Type.Missing, Type.Missing)

' Configure pivot table fields
Dim productField As Excel.PivotField = CType(pivotTable.PivotFields("Product"), Excel.PivotField)
productField.Orientation = Excel.XlPivotFieldOrientation.xlRowField
productField.Position = 1

Dim regionField As Excel.PivotField = CType(pivotTable.PivotFields("Region"), Excel.PivotField)
regionField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField
regionField.Position = 1

Dim salesField As Excel.PivotField = CType(pivotTable.PivotFields("Sales"), Excel.PivotField)
pivotTable.AddDataField(salesField, "Sum of Sales", Excel.XlConsolidationFunction.xlSum)

' Save and cleanup
xlWorkbook.SaveAs("C:\Data\PivotReport.xlsx")
xlWorkbook.Close()
xlApp.Quit()

' Release COM objects to prevent memory leaks
Marshal.ReleaseComObject(pivotTable)
Marshal.ReleaseComObject(pivotCache)
Marshal.ReleaseComObject(xlPivotSheet)
Marshal.ReleaseComObject(xlSheet)
Marshal.ReleaseComObject(xlWorkbook)
Marshal.ReleaseComObject(xlApp)
$vbLabelText   $csharpLabel

Ten przykład Interop tworzy natywną tabelę przestawną programu Excel z produktami w wierszach, regionami w kolumnach i sumą sprzedaży w obszarze danych. Chociaż tworzy on rzeczywisty obiekt tabeli przestawnej w pliku XLSX, wymaga zainstalowania pakietu Microsoft Office oraz starannego zarządzania obiektami COM. Wystarczy pominąć jedno wywołanie Marshal.ReleaseComObject, a w Menedżerze zadań zaczną gromadzić się nieaktualne procesy programu Excel.

Jak zainstalować IronXL przed napisaniem jakiegokolwiek kodu

Zanim przejdziesz do podejścia IronXL, zainstaluj bibliotekę za pomocą menedżera pakietów NuGet:

Install-Package IronXl.Excel
dotnet add package IronXl.Excel
Install-Package IronXl.Excel
dotnet add package IronXl.Excel
SHELL

Nie jest wymagańa instalacja pakietu Office na serwerze, w kontenerze ani na komputerze programisty. IronXL odczytuje i zapisuje pliki XLSX, XLS i CSV całkowicie w zarządzanej pamięci .NET.

Jakie problemy powoduje C# Interop?

Podejście Interop wiąże się z kilkoma istotnymi wyzwaniami, które szybko się kumulują podczas wdrażania w rzeczywistych warunkach. Stack Overflow i inne zasoby programistyczne nadal to zalecają, ponieważ wiele wątków zostało napisanych na początku XXI wieku i od tego czasu zostało zablokowanych — więc porady te są zamrożone w czasie.

Zależności wdrożeniowe — każdy komputer, na którym działa kod, musi mieć zainstalowaną licencjonowaną kopię pakietu Microsoft Office, w tym serwery produkcyjne i agenci kompilacji CI/CD. Powoduje to zarówno wzrost kosztów licencji, jak i złożoność wdrożenia, czego można całkowicie uniknąć dzięki nowoczesnym alternatywom.

Obciążenie związane z zarządzaniem pamięcią — obiekty COM muszą być wyraźnie zwalniane za pomocą Marshal.ReleaseComObject(). Brak nawet jednego obiektu powoduje, że procesy programu Excel zawieszają się w pamięci na czas nieokreślony, co zostało obszernie udokumentówane na Stack Overflow. W długotrwałej usłudze lub aplikacji internetowej ASP.NET staje się to krytycznym wyciekiem zasobów.

Ograniczenia platformy — Interop działa tylko w systemie Windows z zainstalowanym pakietem Office. Nie można go uruchomić w systemie Linux, macOS, w kontenerach Docker ani na platformach bezserwerowych, takich jak Azure Functions lub AWS Lambda. To całkowicie blokuje dostęp do nowoczesnych architektur natywnych dla chmury.

Wąskie gardła wydajności — uruchamianie instancji aplikacji Excel jest powolne i wymaga dużych zasobów. W przypadku przetwarzania wsadowego po stronie serwera, gdzie może zaistnieć potrzeba wygenerowania dziesiątek lub setek raportów, ten nakład związany z uruchomieniem staje się poważnym ograniczeniem przepustowości.

Niestabilność kompatybilności wersji — różne wersje pakietu Office udostępniają nieco inne interfejsy COM. Kod działający w Office 2019 może zachowywać się inaczej w Office 2016 lub Microsoft 365, a użytkownik nie ma możliwości przypisania konkretnej wersji podczas wdrażania. Dokumentacja Microsoftu dotycząca zestawów Office Interop wskazuje te ograniczenia związane z wersjami jako znane ograniczenie.

Niezgodność z CI/CD — w większości środowisk ciągłej integracji nie ma zainstalowanego pakietu Office. Testowanie kodu generującego tabelę przestawną wymaga albo symulacji całej warstwy COM, albo posiadania specjalnego agenta Windows z licencjonowaną instalacją pakietu Office.

W przypadku każdej nowej aplikacji .NET przeznaczonej dla platformy .NET 6 lub nowszej — w tym .NET 10 — te ograniczenia sprawiają, że Interop jest niepraktycznym wyborem.

W jaki sposób IronXL tworzy tabele przestawne bez Interop?

IronXL ma inne podejście do tworzenia tabel przestawnych. Zamiast sterować zewnętrznym procesem programu Excel za pośrednictwem COM, IronXL wczytuje skoroszyt do zarządzanej pamięci .NET, zapewniając bezpośredni dostęp do wartości komórek, formuł i struktury arkusza. Następnie tworzysz agregacje typu pivot przy użyciu standardowych zapytań LINQ i zapisujesz wyniki z powrotem w nowym arkuszu.

Jak utworzyć podsumowanie krzyżowe za pomocą IronXL i LINQ

Poniższy przykład ładuje skoroszyt z danymi sprzedaży, oblicza tabelę krzyżową produktów według regionów i zapisuje podsumowanie w nowym arkuszu — wszystko to bez żadnej zależności od pakietu Office:

using IronXL;
using System.Linq;
using System.Data;

// Load Excel file -- no Office installation required
WorkBook workbook = WorkBook.Load("SalesData.xlsx");
WorkSheet dataSheet = workbook.WorkSheets[0];

// Convert to DataTable for flexible LINQ manipulation
var dataTable = dataSheet.ToDataTable(true); // true = first row as column headers

// Build pivot-style aggregation using LINQ grouping
var pivotData = dataTable.AsEnumerable()
    .GroupBy(row => new {
        Product = row["Product"].ToString(),
        Region = row["Region"].ToString()
    })
    .Select(g => new {
        Product = g.Key.Product,
        Region = g.Key.Region,
        TotalSales = g.Sum(row => Convert.ToDecimal(row["Sales"])),
        AverageSale = g.Average(row => Convert.ToDecimal(row["Sales"])),
        Count = g.Count()
    });

// Create the pivot report worksheet
WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");

// Get distinct row and column values
var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p).ToList();
var regions  = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r).ToList();

// Write column headers
pivotSheet["A1"].Value = "Product / Region";
for (int c = 0; c < regions.Count; c++)
{
    pivotSheet[$"{(char)('B' + c)}1"].Value = regions[c];
}

// Populate data rows
for (int r = 0; r < products.Count; r++)
{
    pivotSheet[$"A{r + 2}"].Value = products[r];
    for (int c = 0; c < regions.Count; c++)
    {
        var sales = pivotData
            .Where(p => p.Product == products[r] && p.Region == regions[c])
            .Select(p => p.TotalSales)
            .FirstOrDefault();
        pivotSheet[$"{(char)('B' + c)}{r + 2}"].Value = sales;
    }
}

// Add a totals row using Excel SUM formulas
int totalRow = products.Count + 2;
pivotSheet[$"A{totalRow}"].Value = "Total";
for (int c = 0; c < regions.Count; c++)
{
    char col = (char)('B' + c);
    pivotSheet[$"{col}{totalRow}"].Formula = $"=SUM({col}2:{col}{totalRow - 1})";
}

// Apply currency formatting to the data range
var dataRange = pivotSheet[$"B2:{(char)('B' + regions.Count - 1)}{totalRow}"];
dataRange.FormatString = "$#,##0.00";

workbook.SaveAs("PivotReport.xlsx");
using IronXL;
using System.Linq;
using System.Data;

// Load Excel file -- no Office installation required
WorkBook workbook = WorkBook.Load("SalesData.xlsx");
WorkSheet dataSheet = workbook.WorkSheets[0];

// Convert to DataTable for flexible LINQ manipulation
var dataTable = dataSheet.ToDataTable(true); // true = first row as column headers

// Build pivot-style aggregation using LINQ grouping
var pivotData = dataTable.AsEnumerable()
    .GroupBy(row => new {
        Product = row["Product"].ToString(),
        Region = row["Region"].ToString()
    })
    .Select(g => new {
        Product = g.Key.Product,
        Region = g.Key.Region,
        TotalSales = g.Sum(row => Convert.ToDecimal(row["Sales"])),
        AverageSale = g.Average(row => Convert.ToDecimal(row["Sales"])),
        Count = g.Count()
    });

// Create the pivot report worksheet
WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");

// Get distinct row and column values
var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p).ToList();
var regions  = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r).ToList();

// Write column headers
pivotSheet["A1"].Value = "Product / Region";
for (int c = 0; c < regions.Count; c++)
{
    pivotSheet[$"{(char)('B' + c)}1"].Value = regions[c];
}

// Populate data rows
for (int r = 0; r < products.Count; r++)
{
    pivotSheet[$"A{r + 2}"].Value = products[r];
    for (int c = 0; c < regions.Count; c++)
    {
        var sales = pivotData
            .Where(p => p.Product == products[r] && p.Region == regions[c])
            .Select(p => p.TotalSales)
            .FirstOrDefault();
        pivotSheet[$"{(char)('B' + c)}{r + 2}"].Value = sales;
    }
}

// Add a totals row using Excel SUM formulas
int totalRow = products.Count + 2;
pivotSheet[$"A{totalRow}"].Value = "Total";
for (int c = 0; c < regions.Count; c++)
{
    char col = (char)('B' + c);
    pivotSheet[$"{col}{totalRow}"].Formula = $"=SUM({col}2:{col}{totalRow - 1})";
}

// Apply currency formatting to the data range
var dataRange = pivotSheet[$"B2:{(char)('B' + regions.Count - 1)}{totalRow}"];
dataRange.FormatString = "$#,##0.00";

workbook.SaveAs("PivotReport.xlsx");
Imports IronXL
Imports System.Linq
Imports System.Data

' Load Excel file -- no Office installation required
Dim workbook As WorkBook = WorkBook.Load("SalesData.xlsx")
Dim dataSheet As WorkSheet = workbook.WorkSheets(0)

' Convert to DataTable for flexible LINQ manipulation
Dim dataTable As DataTable = dataSheet.ToDataTable(True) ' True = first row as column headers

' Build pivot-style aggregation using LINQ grouping
Dim pivotData = dataTable.AsEnumerable() _
    .GroupBy(Function(row) New With {
        Key .Product = row("Product").ToString(),
        Key .Region = row("Region").ToString()
    }) _
    .Select(Function(g) New With {
        Key .Product = g.Key.Product,
        Key .Region = g.Key.Region,
        Key .TotalSales = g.Sum(Function(row) Convert.ToDecimal(row("Sales"))),
        Key .AverageSale = g.Average(Function(row) Convert.ToDecimal(row("Sales"))),
        Key .Count = g.Count()
    })

' Create the pivot report worksheet
Dim pivotSheet As WorkSheet = workbook.CreateWorkSheet("PivotReport")

' Get distinct row and column values
Dim products = pivotData.Select(Function(p) p.Product).Distinct().OrderBy(Function(p) p).ToList()
Dim regions = pivotData.Select(Function(p) p.Region).Distinct().OrderBy(Function(r) r).ToList()

' Write column headers
pivotSheet("A1").Value = "Product / Region"
For c As Integer = 0 To regions.Count - 1
    pivotSheet($"{ChrW(AscW("B"c) + c)}1").Value = regions(c)
Next

' Populate data rows
For r As Integer = 0 To products.Count - 1
    pivotSheet($"A{r + 2}").Value = products(r)
    For c As Integer = 0 To regions.Count - 1
        Dim sales = pivotData _
            .Where(Function(p) p.Product = products(r) AndAlso p.Region = regions(c)) _
            .Select(Function(p) p.TotalSales) _
            .FirstOrDefault()
        pivotSheet($"{ChrW(AscW("B"c) + c)}{r + 2}").Value = sales
    Next
Next

' Add a totals row using Excel SUM formulas
Dim totalRow As Integer = products.Count + 2
pivotSheet($"A{totalRow}").Value = "Total"
For c As Integer = 0 To regions.Count - 1
    Dim col As Char = ChrW(AscW("B"c) + c)
    pivotSheet($"{col}{totalRow}").Formula = $"=SUM({col}2:{col}{totalRow - 1})"
Next

' Apply currency formatting to the data range
Dim dataRange = pivotSheet($"B2:{ChrW(AscW("B"c) + regions.Count - 1)}{totalRow}")
dataRange.FormatString = "$#,##0.00"

workbook.SaveAs("PivotReport.xlsx")
$vbLabelText   $csharpLabel

W ten sposób powstaje takie samo podsumowanie w formie tabeli krzyżowej, jakie uzyskano by z natywnej tabeli przestawnej programu Excel. Masz pełną kontrolę programową nad każdą komórką, formułą i ciągiem formatującym — i nie musisz zajmować się czyszczeniem obiektów COM.

Jak utworzyć tabelę przestawną w programie Excel przy użyciu C# Interop vs IronXL: Obraz 1 — Oryginalny plik Excel vs. utworzona tabela przestawna pokazująca komórki.

!{--01001100010010010100001001010010010000010101001001011001010111110100011101000101010101000101111101010011010101000100000101010010010101000100010101000100010111110101011101001001010100010010000101111101010000010100100100111101000100010101010100001101010100010111110101010001010010010010010100000101001100010111110100001001001100010011110100001101001011--}

Jak tworzyć dynamiczne podsumowania za pomocą formuł programu Excel?

W sytuacjach, w których chcesz, aby arkusz podsumowujący był aktualizowany na bieżąco — automatycznie przeliczany przy każdej zmianie danych źródłowych — IronXL pozwala na wpisywanie ciągów formuł Excel bezpośrednio do komórek. Daje to efekt podobny do automatycznego odświeżania tabeli przestawnej, bez żadnej zależności od Interop.

Kluczowymi funkcjami są tutaj SUMIFS i COUNTIFS. SUMIFS sumuje zakres na podstawie warunków kolumn opartych na wielu kryteriach; COUNTIFS zlicza pasujące wiersze. Oba akceptują odniesienia do nazwanych arkuszy, więc możesz skierować swój arkusz podsumowujący bezpośrednio do arkusza danych źródłowych, podając jego nazwę.

Jak pisać agregacje oparte na formułach za pomocą IronXL

using IronXL;
using System.Data;

string inputPath  = "SalesData.xlsx";
string outputPath = "DynamicSummary.xlsx";

WorkBook workbook  = WorkBook.Load(inputPath);
WorkSheet dataSheet = workbook.WorkSheets[0];

// Name the data sheet so formula references are stable
dataSheet.Name = "DataSheet";

// Convert to DataTable to enumerate unique product/region combinations
DataTable dataTable = dataSheet.ToDataTable(true);

WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");

// Get unique product-region pairs
var uniqueCombos = dataTable.AsEnumerable()
    .Select(row => new {
        Product = row["Product"].ToString(),
        Region  = row["Region"].ToString()
    })
    .Distinct()
    .OrderBy(x => x.Product)
    .ThenBy(x => x.Region)
    .ToList();

// Header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";

// Populate rows with live SUMIFS / COUNTIFS formulas
for (int i = 0; i < uniqueCombos.Count; i++)
{
    int rowIndex = i + 2;
    var combo = uniqueCombos[i];

    summarySheet[$"A{rowIndex}"].Value = combo.Product;
    summarySheet[$"B{rowIndex}"].Value = combo.Region;

    summarySheet[$"C{rowIndex}"].Formula =
        $"=SUMIFS(DataSheet!C:C,DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";

    summarySheet[$"D{rowIndex}"].Formula =
        $"=COUNTIFS(DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
}

// Grand total row
int totalRow = uniqueCombos.Count + 2;
summarySheet[$"A{totalRow}"].Value = "Total";
summarySheet[$"C{totalRow}"].Formula = $"=SUM(C2:C{totalRow - 1})";
summarySheet[$"D{totalRow}"].Formula = $"=SUM(D2:D{totalRow - 1})";

workbook.SaveAs(outputPath);
using IronXL;
using System.Data;

string inputPath  = "SalesData.xlsx";
string outputPath = "DynamicSummary.xlsx";

WorkBook workbook  = WorkBook.Load(inputPath);
WorkSheet dataSheet = workbook.WorkSheets[0];

// Name the data sheet so formula references are stable
dataSheet.Name = "DataSheet";

// Convert to DataTable to enumerate unique product/region combinations
DataTable dataTable = dataSheet.ToDataTable(true);

WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");

// Get unique product-region pairs
var uniqueCombos = dataTable.AsEnumerable()
    .Select(row => new {
        Product = row["Product"].ToString(),
        Region  = row["Region"].ToString()
    })
    .Distinct()
    .OrderBy(x => x.Product)
    .ThenBy(x => x.Region)
    .ToList();

// Header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";

// Populate rows with live SUMIFS / COUNTIFS formulas
for (int i = 0; i < uniqueCombos.Count; i++)
{
    int rowIndex = i + 2;
    var combo = uniqueCombos[i];

    summarySheet[$"A{rowIndex}"].Value = combo.Product;
    summarySheet[$"B{rowIndex}"].Value = combo.Region;

    summarySheet[$"C{rowIndex}"].Formula =
        $"=SUMIFS(DataSheet!C:C,DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";

    summarySheet[$"D{rowIndex}"].Formula =
        $"=COUNTIFS(DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
}

// Grand total row
int totalRow = uniqueCombos.Count + 2;
summarySheet[$"A{totalRow}"].Value = "Total";
summarySheet[$"C{totalRow}"].Formula = $"=SUM(C2:C{totalRow - 1})";
summarySheet[$"D{totalRow}"].Formula = $"=SUM(D2:D{totalRow - 1})";

workbook.SaveAs(outputPath);
Imports IronXL
Imports System.Data
Imports System.Linq

Dim inputPath As String = "SalesData.xlsx"
Dim outputPath As String = "DynamicSummary.xlsx"

Dim workbook As WorkBook = WorkBook.Load(inputPath)
Dim dataSheet As WorkSheet = workbook.WorkSheets(0)

' Name the data sheet so formula references are stable
dataSheet.Name = "DataSheet"

' Convert to DataTable to enumerate unique product/region combinations
Dim dataTable As DataTable = dataSheet.ToDataTable(True)

Dim summarySheet As WorkSheet = workbook.CreateWorkSheet("DynamicSummary")

' Get unique product-region pairs
Dim uniqueCombos = dataTable.AsEnumerable() _
    .Select(Function(row) New With {
        .Product = row("Product").ToString(),
        .Region = row("Region").ToString()
    }) _
    .Distinct() _
    .OrderBy(Function(x) x.Product) _
    .ThenBy(Function(x) x.Region) _
    .ToList()

' Header row
summarySheet("A1").Value = "Product"
summarySheet("B1").Value = "Region"
summarySheet("C1").Value = "Total Sales"
summarySheet("D1").Value = "Count"

' Populate rows with live SUMIFS / COUNTIFS formulas
For i As Integer = 0 To uniqueCombos.Count - 1
    Dim rowIndex As Integer = i + 2
    Dim combo = uniqueCombos(i)

    summarySheet($"A{rowIndex}").Value = combo.Product
    summarySheet($"B{rowIndex}").Value = combo.Region

    summarySheet($"C{rowIndex}").Formula =
        $"=SUMIFS(DataSheet!C:C,DataSheet!A:A,""{combo.Product}"",DataSheet!B:B,""{combo.Region}"")"

    summarySheet($"D{rowIndex}").Formula =
        $"=COUNTIFS(DataSheet!A:A,""{combo.Product}"",DataSheet!B:B,""{combo.Region}"")"
Next

' Grand total row
Dim totalRow As Integer = uniqueCombos.Count + 2
summarySheet($"A{totalRow}").Value = "Total"
summarySheet($"C{totalRow}").Formula = $"=SUM(C2:C{totalRow - 1})"
summarySheet($"D{totalRow}").Formula = $"=SUM(D2:D{totalRow - 1})"

workbook.SaveAs(outputPath)
$vbLabelText   $csharpLabel

Formuły te utrzymują aktywne połączenia z danymi źródłowymi. Gdy ktoś zaktualizuje wartość w DataSheet, program Excel automatycznie przelicza podsumowanie przy następnym otwarciu lub odświeżeniu — zapewniając działanie identyczne jak w przypadku cyklu odświeżania natywnej tabeli przestawnej, bez konieczności stosowania automatyzacji COM.

Po zastosowaniu tego do tego samego skoroszytu z danymi sprzedażowymi, który był użyty w poprzednim przykładzie, wynik wygląda następująco:

Jak utworzyć tabelę przestawną w programie Excel przy użyciu C# Interop vs IronXL: Obraz 2 — Dynamiczne podsumowania w języku C# wyświetlone w kontekście.

To podejście oparte na formułach umożliwia również dodawanie formatowania warunkówego, pasków danych lub zestawów ikon do komórek podsumowujących za pomocą interfejsu API formatowania komórek IronXL, dzięki czemu raporty są przejrzyste wizualnie bez konieczności ręcznej pracy w interfejsie użytkownika programu Excel.

Jak wypadają te dwa podejścia w porównaniu?

Przed wyborem podejścia warto zapoznać się z zestawieniem zalet i wad poszczególnych opcji. Poniższa tabela przedstawia najważniejsze aspekty związane z produkcyjnym programowaniem w środowisku .NET:

C# Interop a IronXL w tworzeniu tabel przestawnych
Aspekt C# Interop IronXL
Wymagane biuro Tak — pełna instalacja na każdym komputerze Nie — samodzielny pakiet NuGet
Obsługa platform Tylko dla systemu Windows Windows, Linux, macOS, Docker
Zarządzanie pamięcią Wymagane ręczne czyszczenie COM Automatyczne zbieranie śmieći w .NET
Złożoność wdrożenia Wysoki — licencjonowanie i instalacja pakietu Office Niski — pojedyncze odwołanie do biblioteki DLL
Wydajność Powolne — obciążenie związane z uruchamianiem procesu w Excelu Szybkość — obliczenia w pamięci
Kompatybilność z chmurą Nie — zablokowane w Azure Functions, AWS Lambda Tak — działa na każdej platformie chmurowej
Natywny obiekt tabeli przestawnej Tak — pełna tabela przestawna w Excelu Nie — odpowiednik oparty na agregacji
Szybkość rozwoju Powolne — złożoność COM Szybki — płynnie działający interfejs API
Obsługa .NET 10 Ograniczone — problemy z powiązaniem COM Pełna wersja — przeznaczona dla nowoczesnego środowiska .NET

Jedynym scenariuszem, w którym Interop ma wyraźną przewagę, jest sytuacja, gdy konkretnie potrzebny jest natywny obiekt tabeli przestawnej programu Excel osadzony w pliku XLSX — na przykład, jeśli użytkownicy końcowi muszą z nim współpracować za pomocą wbudowanego interfejsu użytkownika tabeli przestawnej programu Excel (drilling down, filtrowanie, interaktywna zmiana funkcji agregacji). W każdym innym scenariuszu podejście IronXL jest szybsze w pisaniu, łatwiejsze we wdrażaniu i znacznie bardziej przenośne.

Które podejście wybrać?

Właściwy wybór zależy od środowiska wdrożeniowego i potrzeb użytkowników.

Wybierz C# Interop tylko wtedy, gdy:

  • Użytkownicy potrzebują natywnych obiektów tabel przestawnych programu Excel, którymi mogą manipulować interaktywnie w interfejsie użytkownika programu Excel
  • Twoim celem jest zamknięte środowisko komputerów stacjonarnych z systemem Windows, w którym na każdym komputerze na pewno zainstalowany jest pakiet Office
  • Utrzymujesz starszy kod .NET Framework, który już opiera się na Interop, a przepisanie go nie jest obecnie uzasadnione

Wybierz IronXL, gdy:

  • Wdrażasz na serwerze, w kontenerze lub w dowolnym środowisku chmurowym (Azure, AWS, GCP)
  • Potrzebujesz obsługi wielu platform, w tym systemów Linux, macOS lub kompilacji opartych na Dockerze
  • Chcesz mieć przejrzysty, łatwy w utrzymaniu kod bez zarządzania cyklem życia COM
  • Twoim celem jest .NET 5, 6, 7, 8, 9 lub 10
  • Chcesz uniknąć opłat licencyjnych za pakiet Microsoft Office w infrastrukturze serwerowej
  • Potrzebujesz szybkiego przetwarzania wsadowego wielu skoroszytów bez uruchamiania procesu Excel dla każdego pliku

W przypadku zdecydowanej większości nowoczesnych aplikacji .NET IronXL jest praktycznym wyborem. Wynik oparty na agregacji spełnia wszystkie rzeczywiste wymagania dotyczące raportowania, a w zamian zyskujesz pełną przenośność.

Możesz zapoznać się z dalszymi możliwościami — w tym formatowaniem komórek, obliczaniem formuł, sprawdzaniem poprawności danych i generowaniem wykresów — w dokumentacji IronXL oraz bibliotece przykładów IronXL.

Jak już dziś rozpocząć pracę z IronXL?

Biblioteka IronXL jest dostępna w serwisie NuGet, a dodanie jej do dowolnego projektu .NET zajmuje mniej niż minutę:

Install-Package IronXl.Excel
dotnet add package IronXl.Excel
Install-Package IronXl.Excel
dotnet add package IronXl.Excel
SHELL

Po zainstalowaniu można załadować istniejący skoroszyt lub utworzyć nowy, odczytywać i zapisywać wartości komórek, stosować formuły, ustawiać formatowanie tekstu oraz zapisywać pliki w formacie XLSX — wszystko to za pomocą przejrzystego, dobrze udokumentówanego interfejsu API. Nie jest wymagańe COM, zależność od pakietu Office ani specjalna konfiguracja serwera.

Pełna dokumentacja API znajduje się w przewodniku wprowadzającym do IronXL, przewodniku migracji C# Excel Interop oraz przykładach kodu IronXL. Możesz również porównać IronXL z innymi bibliotekami IronXL w artykułach porównawczych dotyczących IronXL.

Bezpłatna licencja próbna pozwala przetestować pełną funkcjonalność w ramach własnego projektu przed podjęciem ostatecznej decyzji. Gdy będziesz gotowy do wdrożenia w środowisku produkcyjnym, komercyjna licencja IronXL usunie znak wodny wersji próbnej i zapewni priorytetowe wsparcie techniczne. Zacznij od bezpłatnej wersji próbnej i przekonaj się, o ile prostsza może być wielopłatformowa automatyzacja programu Excel.

Często Zadawane Pytania

Jak mogę tworzyć tabele przestawne w Excelu przy użyciu języka C# bez Interop?

Możesz tworzyć tabele przestawne w Excelu przy użyciu języka C# bez Interop, korzystając z biblioteki IronXL, która oferuje zaawansowane możliwości manipulacji danymi niezależnie od zależności z pakietem Office.

Jakie są zalety korzystania z IronXL do generowania tabel przestawnych?

IronXL pozwala programistom generować tabele przestawne bez konieczności korzystania z Excel Interop, co eliminuje potrzebę instalacji pakietu Office i zmniejsza złożoność wdrożenia.

Czy IronXL jest kompatybilny z aplikacjami .NET?

Tak, IronXL jest w pełni kompatybilny z aplikacjami .NET, zapewniając łatwe w użyciu API do operacji w Excelu, w tym tworzenia tabel przestawnych.

Czy IronXL wymaga zainstalowania programu Excel na serwerze?

Nie, IronXL nie wymaga instalacji programu Excel na serwerze. Działa niezależnie, co pozwala na płynną integrację z aplikacjami po stronie serwera.

Czy mogę przetwarzać dane w Excelu za pomocą IronXL?

Tak, IronXL oferuje rozbudowane funkcje manipulacji danymi, umożliwiające programistom tworzenie, modyfikowanie i analizowanie danych w Excelu, w tym tworzenie tabel przestawnych.

Dlaczego programiści mogą preferować IronXL zamiast tradycyjnych metod interoperacyjności?

Programiści mogą preferować IronXL zamiast tradycyjnych metod Interop ze względu na brak zależności od pakietu Office, prostsze wdrożenie oraz wszechstronną funkcjonalność w zakresie operacji w programie Excel.

Jakie funkcje oferuje IronXL do manipulacji danymi w Excelu?

IronXL oferuje takie funkcje, jak odczyt i zapis plików Excel, tworzenie i edycja arkuszy kalkulacyjnych oraz generowanie tabel przestawnych, a wszystko to bez konieczności korzystania z Excel Interop.

Jordi Bardia
Inżynier oprogramowania
Jordi jest najbardziej biegły w Pythonie, C# i C++. Kiedy nie wykorzystuje swoich umiejętności w Iron Software, programuje gry. Dzieląc odpowiedzialność za testowanie produktów, rozwój produktów i badania, Jordi wnosi ogromną wartość do ciągłej poprawy produktów. Różnorodne doświadczenia ...
Czytaj więcej

Zespol wsparcia Iron

Jestesmy online 24 godziny, 5 dni w tygodniu.
Czat
Email
Zadzwon do mnie