Reporting für WinForms & WPF: So erstellst du ein vollständiges System mit List & Label

Früher oder später benötigen Desktop-Business-Anwendungen flexibles Reporting: neue Berichte, PDF- und Excel-Exporte, Druckvorschauen oder Layoutänderungen – am besten sofort und ohne neues Release. Für Entwicklungsteams entsteht daraus jedoch schnell ein Wartungsproblem durch individuellen Exportcode und Sonderfälle. List & Label bietet einen pragmatischeren Ansatz: Du integrierst Reporting direkt in deine WinForms- oder WPF-Anwendung und behältst die Kontrolle über Daten, Berechtigungen, Layouts und die User Experience. Dieser Leitfaden zeigt dir, wie du List & Label in reale Geschäftsanwendungen einbindest.

Geschätzte Lesezeit: 13 Minuten

Reporting-System mit List & Label für WinForms- und WPF-Anwendungen

Wichtige Erkenntnisse

  • Bette Reporting direkt in WinForms und WPF ein, ohne ein eigenes Reporting-Subsystem von Grund auf neu zu entwickeln.
  • Behalte Datenzugriff, Sicherheit und Geschäftslogik in deiner Anwendung und stelle nur das Datenbankschema bereit, das Berichte tatsächlich benötigen.
  • Unterstütze interaktives Design, Vorschau, Druck und stille Exporte mit derselben Reporting-Engine.
  • Zentralisiere Vorlagen und Assets mit einer Elementsammlung, sobald lokale Projektdateien nicht mehr skalieren.
  • Verwende kurzlebige ListLabel-Instanzen und einen gemeinsamen Reporting-Service, um die Integration vorhersehbar und wartbar zu halten.

Inhaltsverzeichnis

Was ein „vollständiges Reporting-System“ tatsächlich bedeutet

Ein vollständiges Reporting-System für Desktop-Anwendungen umfasst normalerweise mehr als nur „ein PDF erzeugen“. Typischerweise bedeutet es:

  • Einen Designer, mit dem fortgeschrittene Anwender:innen Berichts-Layouts selbst erstellen oder anpassen können.
  • Ein DataBinding-Modell, das mit deinen bestehenden Datensätzen, SQL-Verbindungen, Objekten, XML, JSON oder benutzerdefinierten Datenprovidern funktioniert.
  • Vorschau und Drucken innerhalb deiner Anwendung.
  • Export in mehrere Formate wie PDF, Excel, Word, HTML, Bilder und mehr.
  • Automatisierung für Szenarien wie One-Click-Exporte, Hintergrundverarbeitung, E-Mail-Versand oder Archivierung.
  • Ein Bereitstellungsmodell, das zuverlässig auf Kundensystemen funktioniert.

Genau diese Lücke schließt List & Label.


Was List & Label macht und wo es eingesetzt wird

List & Label ist weder ein separates SaaS noch ein Reporting-Server. Es handelt sich um eine .NET-Reporting-Komponente, die du Anwender:innen übergibst. Du lieferst sie mit deiner Desktop-Anwendung aus und rufst sie wie jede andere Bibliothek aus deinem Code auf.

Zur Laufzeit bleiben die Zuständigkeiten klar getrennt:

  • Deine Anwendung übernimmt Authentifizierung, Autorisierung, Navigation und Datenzugriff.
  • Dein Datenprovider entscheidet, welche Daten für Berichte verfügbar sind.
  • List & Label stellt Designer, Rendering-Engine, Vorschau, Druckpipeline und Exporte bereit.

Diese Trennung ist entscheidend.

Ein Reporting-System wird schnell unübersichtlich, wenn die Reporting-Schicht direkt auf deine Datenbank zugreift oder die Geschäftslogik umgeht. Mit List & Label bleibt deine Anwendung das führende System und die Sicherheitsgrenze. Die Reporting-Engine arbeitet nur mit den Daten, die du ihr explizit zur Verfügung stellst.


Integrationsübersicht für WinForms und WPF

Die gute Nachricht: Der grundlegende Integrationsablauf ist für beide UI-Stacks nahezu identisch. Die typischen Schritte sind:

  1. Füge die erforderlichen List & Label-Assemblies oder NuGet-Pakete hinzu.
  2. Erstelle und konfiguriere eine ListLabel-Instanz.
  3. Binde sie an eine Datenquelle oder einen Datenprovider.
  4. Öffne den Designer mit Design(), wenn Anwender:innen einen Bericht erstellen oder bearbeiten möchten.
  5. Rufe Print() für interaktive Vorschau- und Druckabläufe auf.
  6. Rufe Export() für stille oder gesteuerte Exporte auf.

Dieses gemeinsame Modell erleichtert es dir, die Reporting-Logik an einer Stelle zu bündeln – selbst in gemischten WinForms/WPF-Umgebungen.


Zentrale Konzepte, die du wirklich brauchst

Die ListLabel-Komponente

Das Zentrum der Integration ist die Klasse ListLabel aus combit.Reporting. Sie fungiert als Instanz der Reporting-Engine für einen bestimmten Vorgang und ist verantwortlich für:

  • DataBinding über DataSource und optional DataMember
  • Berichtsdesign mit Design()
  • Rendering und Drucken mit Print()
  • Dateierstellung mit Export()
  • Konfiguration wie Projektdatei, Projekttyp, Exportoptionen, Ziel für die Vorschau und mehr

In der Praxis ist das sauberste Muster meist eine ListLabel-Instanz pro Reporting-Vorgang.

using combit.Reporting;

using (var ll = new ListLabel())
{
    ll.LicensingInfo = "your-license-key";
    // configure data source, project, and output, see below for a full sample
}

Das sorgt dafür, dass Lebensdauer und Ressourcennutzung klar und nachvollziehbar bleiben.


Datenprovider und DataSource

List & Label stellt keine eigene Verbindung zu deiner Datenbank her. Deine Anwendung ist für den Datenzugriff verantwortlich und übergibt eine Datenquelle an die Reporting-Engine. Das ist ein Vorteil. Denn so behält deine Anwendung die Kontrolle über:

  • Berechtigungen
  • Filterung
  • Mandantengrenzen
  • Caching
  • Geschäftslogik
  • Benennung und Strukturierung des Berichtsschemas

Du kannst viele verschiedene Datenquellen anbinden, darunter:

  • ADO.NET-Datasets
  • SQL-Verbindungen (SQL Server, Oracle, DB2, SQLite, …)
  • XML, JSON und CSV
  • Objektsammlungen
  • Benutzerdefinierte Datenprovider

Zum Beispiel bei Verwendung von SQL Server:

using combit.Reporting;
using combit.Reporting.DataProviders;
using System.Data.SqlClient;

var connection = new SqlConnection(Properties.Settings.Default.ConnectionString);
var provider = new SqlConnectionDataProvider(connection);

using (var ll = new ListLabel())
{
    ll.LicensingInfo = "your-license-key";
    ll.DataSource = provider;

    ll.Design();
}

Für tabellenbasierte oder hierarchische Daten kannst du zusätzlich DataMember setzen:

ll.DataSource = CreateDataSet();
ll.DataMember = "Products";

Für Master-Detail-Szenarien wie Rechnungen kannst du von der Kopf-Tabelle ausgehen und Details als verknüpfte Berichtscontainer bereitstellen:

ll.DataSource = CreateDataSet();
ll.DataMember = "InvoiceHeader";
ll.AutoMasterMode = LlAutoMasterMode.AsVariables;

Dieses Muster eignet sich gut für Formulare, Rechnungen und ähnliche dokumentenbasierte Berichte.


Projekttypen und Projektdateien

List & Label unterstützt Projekttypen wie Listen, Etiketten, Karten und mehr. Du kannst:

  • Den Projekttyp mit AutoProjectType festlegen
  • Ein neues Projekt von Grund auf erstellen oder mit AutoProjectFile auf eine bestimmte Projektdatei verweisen

Beispiel:

using (var ll = new ListLabel())
{
    ll.LicensingInfo = "your-license-key";
    ll.DataSource = CreateDataSet();

    ll.AutoProjectType = LlProject.List;

    ll.Design();
    ll.Print();
}

Das reicht aus, damit Anwender:innen einmal designen und denselben Bericht anschließend an mehreren Stellen deiner Oberfläche wiederverwenden können.


Drucken, Vorschau und Export

Print() ist der einfachste Einstiegspunkt, wenn Anwender:innen mit integrierten Vorschau- und Druckabläufen interagieren sollen.

Für automatisierte Ausgaben verwendest du Export() mit ExportConfiguration.

var config = new ExportConfiguration(
    LlExportTarget.Pdf,
    @"C:\output\report.pdf",
    @"Reports\MyList.lst")
{
    ShowResult = true
};

ll.Export(config);

Bei Bedarf kannst du das Verhalten auch über Exportoptionen steuern, aber Export() ist in der Regel der sauberere Ansatz für stille oder kontrollierte Ausgaben.


WinForms-Integration

Schnelleinrichtung

Für einfache Szenarien kannst du die List & Label-Pakete hinzufügen, das Projekt erstellen und die Integration über die Visual Studio-Toolbox nutzen. Das ist für Experimente und interne Tools völlig ausreichend.

Für Produktivcode ist es jedoch meist besser, den Großteil der Reporting-Konfiguration im Code zu halten. So lässt sich alles leichter überprüfen, versionieren und testen.

Laufzeiterstellung im Code

Ein pragmatisches WinForms-Muster ist es, kurzlebige ListLabel-Instanzen für spezifische Aktionen wie Design, Druck oder Export zu erstellen.

using combit.Reporting;
using combit.Reporting.DataProviders;
using System.Data.SqlClient;

public void DesignReports()
{
    using (var ll = new ListLabel())
    {
        ll.LicensingInfo = "your-license-key";

        var connection = new SqlConnection(Properties.Settings.Default.ConnectionString);
        var provider = new SqlConnectionDataProvider(connection);
        ll.DataSource = provider;

        ll.AutoProjectType = LlProject.List;

        ll.Design();
    }
}

Das vermeidet versteckten globalen Zustand und hält Reporting-Aktionen isoliert.


WPF-Integration

Die Engine-API ist in WPF identisch. Der Unterschied liegt hauptsächlich darin, wie du Vorschau- und Designer-Erlebnisse einbindest.

Ein sauberes Muster ist es, die Reporting-Logik in eine Service-Klasse auszulagern und deine Views schlank zu halten.

using combit.Reporting;

public class ReportingService
{
    private readonly string _license;

    public ReportingService(string license)
    {
        _license = license;
    }

    public void ExportCustomerListToPdf(string projectFilePath, string outputPath)
    {
        using (var ll = new ListLabel())
        {
            ll.LicensingInfo = _license;
            ll.DataSource = CreateCustomerDataSet();

            var config = new ExportConfiguration(
                LlExportTarget.Pdf,
                outputPath,
                projectFilePath)
            {
                ShowResult = true
            };

            ll.Export(config);
        }
    }
}

Derselbe Service kann aus Commands, ViewModels oder Code-Behind verwendet werden.


Einbettung von Vorschau und Designer

Eingebettete Vorschau in WinForms

Wenn du kein separates Vorschaufenster möchtest, kannst du das Vorschau-Control von List & Label direkt in deinem eigenen Formular hosten.

Die Grundidee ist:
• Platziere ein Vorschau-Control in deiner WinForms-Oberfläche
• Setze es als Ziel für die Vorschau
• Rufe Print() auf

Ein typisches Setup sieht so aus:

public partial class PreviewForm : Form
{
    public PreviewForm()
    {
        InitializeComponent();
    }

    public ListLabelPreviewControl PreviewControl => listLabelPreviewControl1;

    public void ShowReport(DataSet ds, string projectPath, string license)
    {
        using (var ll = new ListLabel())
        {
            ll.LicensingInfo = license;
            ll.DataSource = ds;
            ll.AutoDestination = LlPrintMode.PreviewControl;
            ll.PreviewControl = listLabelPreviewControl1;
            ll.AutoProjectFile = projectPath;

            ll.Print();
        }

        ShowDialog();
    }
}

Damit erhältst du native Vorschau-, Navigations-, Such- und Exportfunktionen, ohne einen eigenen Viewer entwickeln zu müssen.

Eingebettete Vorschau in WPF

In WPF bleibt die Engine gleich. Nur das Hosting ändert sich.

Ein gängiger Ansatz ist die Verwendung eines WindowsFormsHost für das Vorschau-Control. So kannst du Reporting-Funktionalität vom Rest deiner WPF-Anwendung trennen und dennoch eine integrierte Vorschau bieten.

Eingebetteter Designer

Wenn der Designer innerhalb deiner Anwendung statt in einem separaten Fenster laufen soll, verwende DesignerControl in WinForms.

public partial class DesignerForm : Form
{
    private readonly ListLabel _ll;

    public DesignerForm(ListLabel ll)
    {
        InitializeComponent();
        _ll = ll;
        designerControl1.ListLabel = _ll;
    }
}

In WPF kannst du dieses WinForms-Control ebenfalls über WindowsFormsHost einbinden oder alternativ einen dedizierten WinForms-Dialog für Designer-Workflows öffnen.


Export von Berichten und Automatisierung der Ausgabe

Exporte sind meist der Punkt, an dem ein Reporting-System wirklich nützlich wird. Interaktive Vorschau ist gut, aber viele Desktop-Anwendungen benötigen zusätzlich:

  • One-Click-PDF-Erstellung
  • Excel-Exporte für Fachabteilungen
  • Hintergrundgenerierung von Dateien
  • Archivierte Ausgaben
  • Optionalen E-Mail-Versand

Ein einfacher Export-Ablauf sieht so aus:

using (var ll = new ListLabel())
{
    ll.LicensingInfo = "your-license-key";
    ll.DataSource = CreateDataSet();

    string projectPath = @"C:\Reports\MyReport.lst";
    string exportPath  = @"C:\Exports\MyReport.pdf";

    var config = new ExportConfiguration(
        LlExportTarget.Pdf,
        exportPath,
        projectPath
    )
    {
        ShowResult = false
    };

    ll.Export(config);
}

Von dort aus kannst du die erzeugte Datei an deine eigene Anwendungslogik übergeben, z. B. für Archivierung, Upload oder Versand.

Das ist oft die beste Aufgabentrennung: List & Label erzeugt die Ausgabe, dein Code übernimmt Orchestrierung und compliance-relevante Workflows.


Anpassen des Designers und Nutzung einer Elementsammlung

Steuerung des Designers

Du möchtest in der Regel nicht, dass jede:r Anwender:in Zugriff auf alle Designfunktionen hat. List & Label ermöglicht es dir, den Designer so anzupassen, dass er sich wie ein Teil deines Produkts anfühlt. Je nach Bedarf kannst du z. B.:

  • Beschriftungen und Branding ändern
  • Funktionen für Nicht-Admins einschränken
  • Menüpunkte ausblenden
  • Exportziele begrenzen
  • Unterschiedliche Designmöglichkeiten je Rolle anbieten

Das ist in echten Anwendungen wichtig. Reporting ist selten „one size fits all“.

Verwendung einer Elementsammlung für zentrale Projektspeicherung

Im kleinen Maßstab reicht es, .lst- und .lbl-Dateien lokal zu speichern. Im größeren Maßstab wird das jedoch schwieriger zu verwalten:

  • Mehrere Anwender:innen bearbeiten Vorlagen
  • Geteilte Assets wie Bilder oder Drilldown-Ziele
  • Backups
  • Konsistente Versionen auf verschiedenen Rechnern

Eine Elementsammlung löst dieses Problem, indem Projekte und zugehörige Assets zentral gespeichert werden, häufig in einer Datenbank.

Aus .NET heraus kannst du Repository-Elemente per URI referenzieren:

ll.AutoProjectFile = "repository://f3bd1a78-8af2-4aab-93c3-3e5b9fa9d87c";

Das ist oft der sauberste Weg, sobald Berichte zu gemeinsamen Anwendungsressourcen werden statt zu lokalen Entwicklerartefakten.


Bereitstellung und Lizenzierung

Die Bereitstellung in .NET-Desktop-Anwendungen ist einfach. In der Regel lieferst du die erforderlichen List & Label-Assemblies und Binärdateien zusammen mit deiner Anwendung aus. Du musst keinen separaten Reporting-Server aufbauen, um Design-, Vorschau- und Exportfunktionen bereitzustellen. Eine Registrierung ist ebenfalls nicht erforderlich.

Zur Laufzeit setzt du LicensingInfo auf jeder ListLabel-Instanz mit deinem Lizenzschlüssel.

ll.LicensingInfo = "your-license-key";

Achte darauf, dass deine Produktivbereitstellung mit den offiziellen Lizenz- und Weitergaberichtlinien der eingesetzten Version übereinstimmt – besonders bei Installern oder Distribution an kundenseitig verwaltete Umgebungen.


End-to-End-Beispiel: Kunden-Reporting-System

Nehmen wir an, du hast eine WinForms- oder WPF-Desktop-Anwendung mit SQL Server im Backend und du möchtest Anwender:innen Folgendes ermöglichen:

  • Berichtsvorlagen erstellen
  • Berichte in der Vorschau anzeigen
  • Berichte drucken
  • Berichte als PDF exportieren
  • Vorlagen später in eine zentrale Elementsammlung verschieben

Mithilfe des folgenden Beispiels kannst du dir diese Struktur in der Praxis aufbauen.

Pakete hinzufügen

dotnet add package combit.ListLabel31
dotnet add package combit.ListLabel31.SqlConnectionDataProvider

Gemeinsamer Datenprovider-Helfer

using System.Data.SqlClient;
using combit.Reporting.DataProviders;

public static class ReportingData
{
    public static SqlConnectionDataProvider CreateNorthwindProvider()
    {
        var builder = new SqlConnectionStringBuilder
        {
            DataSource     = Properties.Settings.Default.SQLServerInstance,
            UserID         = Properties.Settings.Default.SQLUser,
            Password       = Properties.Settings.Default.SQLPassword,
            InitialCatalog = "Northwind"
        };

        var connection = new SqlConnection(builder.ConnectionString);
        return new SqlConnectionDataProvider(connection);
    }
}

Zentraler Reporting-Service

using combit.Reporting;

public class ReportingService
{
    private readonly string _license;

    public ReportingService(string license)
    {
        _license = license;
    }

    private ListLabel CreateListLabel(object dataSource)
    {
        return new ListLabel
        {
            LicensingInfo = _license,
            DataSource = dataSource
        };
    }

    public void DesignReport(string projectPath, object dataSource)
    {
        using var ll = CreateListLabel(dataSource);
        ll.AutoProjectFile = projectPath;
        ll.Design();
    }

    public void PrintReport(string projectPath, object dataSource)
    {
        using var ll = CreateListLabel(dataSource);
        ll.AutoProjectFile = projectPath;
        ll.Print();
    }

    public void ExportReport(string projectPath, object dataSource, LlExportTarget target, string exportPath)
    {
        using var ll = CreateListLabel(dataSource);
        var config = new ExportConfiguration(target, exportPath, projectPath)
        {
            ShowResult = true
        };
        ll.Export(config);
    }
}

Berichte designen

private void btnDesignReports_Click(object sender, EventArgs e)
{
    var service = new ReportingService("your-license-key");
    service.DesignReport(@"Reports\CustomerList.lst", ReportingData.CreateNorthwindProvider());
}

Berichte drucken

private void btnPrintReport_Click(object sender, EventArgs e)
{
    var service = new ReportingService("your-license-key");
    service.PrintReport(@"Reports\CustomerList.lst", ReportingData.CreateNorthwindProvider());
}

Berichte als PDF exportieren

private void btnExportPdf_Click(object sender, EventArgs e)
{
    var service = new ReportingService("your-license-key");
    service.ExportReport(
        @"Reports\CustomerList.lst",
        ReportingData.CreateNorthwindProvider(),
        LlExportTarget.Pdf,
        @"C:\Exports\CustomerList.pdf");
}

Später auf Repository-basierte Vorlagen umstellen

Sobald lokale Dateien unübersichtlich werden, wechselst du von Dateipfaden zu Repository-URIs:

ll.AutoProjectFile = "repository://f3bd1a78-8af2-4aab-93c3-3e5b9fa9d87c";

Das ist ein sauberer Migrationspfad von „ein paar Reportdateien“ zu „Reporting ist jetzt eine zentrale Produktfunktion“.


Best Practices

Sobald die Grundlagen funktionieren, helfen einige Muster dabei, die Reporting-Schicht langfristig wartbar zu halten.

  • Verwende kurzlebige ListLabelInstanzen für einzelne Operationen. Um DLL-Ladezeiten und Ressourcen-Caching zu optimieren, solltest du zusätzlich eine globale Instanz dauerhaft aktiv halten.
  • Halte den Datenzugriff in deiner Anwendung nicht in den Berichtsdefinitionen, damit Berechtigungen und Geschäftslogik zentral bleiben.
  • Stelle ein domänennahes Datenbankschema bereit, damit der Report Designer die Feldnamen besser verstehen kann.
  • Zentralisiere die Engine-Konfiguration in einem Service, um Lizenzierung, Provider-Anbindung und Standardeinstellungen nicht mehrfach in der Oberfläche zu verteilen.
  • Starte einfach mit einem Provider, einer Vorlage sowie Design() und Print(), und erweitere dann schrittweise um stille Exporte, eingebettete Vorschau, Repository-Speicherung, Parameter und Drilldown.
  • Speichere Vorlagen außerhalb deiner Binärdateien, damit Änderungen keine komplette Neuerstellung der Anwendung erfordern.
  • Nutze möglichst die integrierten Controls für Vorschau und Design, statt diese UI selbst neu zu entwickeln.

Der größte Vorteil liegt nicht nur in weniger Code, sondern darin, die langfristigen Kosten für die Entwicklung eines eigenen Reporting-Subsystems zu vermeiden.


Fazit

Ein vollständiges Reporting-System in einer Desktop-Anwendung geht über das reine Rendern von Dokumenten hinaus. Es geht darum, Anwender:innen eine kontrollierte Möglichkeit zu geben, Berichte zu designen, in der Vorschau anzuzeigen, zu drucken und zu exportieren. So musst du weder ein eigenes Reporting-Framework pflegen noch stößt du bei komplexeren Anforderungen schnell an die Grenzen eines einfachen Tools.

Genau hier spielt List & Label seine Stärken aus.

Deine Anwendung behält die Kontrolle über Daten, Berechtigungen und Abläufe. List & Label übernimmt die Reporting-Engine, die Designoberfläche, die Vorschau und die Ausgabeformate. Diese klare Aufgabentrennung sorgt dafür, dass die Integration schlank, vorhersehbar und sowohl in WinForms als auch in WPF wiederverwendbar bleibt.

Wenn du eine Desktop-Geschäftsanwendung entwickelst und dein Reporting immer komplexer wird, ist es in der Regel kostengünstiger, eine ausgereifte Reporting-Komponente wie List & Label zu nutzen. Die Entwicklung einer eigenen Lösung oder die Nutzung eines einfachen Reporting-Tools mit begrenzten Möglichkeiten ist langfristig gesehen aufwendiger. Lies dazu auch unsere Dev Guides zu den Themen Kaufen oder entwickeln? Warum sich CTOs für List & Label entscheiden und Zu klein gedacht: Warum .NET-Reporting oft neu geschrieben werden muss.

FAQ

Was ist List & Label?

List & Label ist eine .NET Reporting-Komponente, die Design, Rendering, Vorschau, Druck und Exportfunktionen direkt in deine Anwendung integriert.

Funktioniert es sowohl mit WinForms als auch mit WPF?

Ja. Die API der Reporting-Engine ist für beide identisch. Der Hauptunterschied liegt darin, wie Vorschau- und Designer-Controls eingebunden werden.

Kannst du es mit .NET 6, .NET 8 oder dem .NET Framework verwenden?

Ja, abhängig von der verwendeten Version und den unterstützten Zielplattformen. Prüfe die versionsspezifische Dokumentation für genaue Details.

Greift List & Label direkt auf deine Datenbank zu?

Nein. Deine Anwendung ist für den Datenzugriff verantwortlich und übergibt die Daten an die Reporting-Engine.

Kannst du Vorschau und Designer in deine eigene Anwendung einbetten?

Ja. In WinForms kannst du die integrierten Vorschau- und Designer-Controls direkt verwenden. In WPF kannst du diese über WindowsFormsHost einbinden oder in separaten WinForms-Fenstern öffnen.

Empfohlene Artikel