diff --git a/Examples/README.md b/Examples/README.md new file mode 100644 index 00000000..9b7661f6 --- /dev/null +++ b/Examples/README.md @@ -0,0 +1,143 @@ +# Examples Overview + +This directory contains various examples demonstrating different features of Majorsilence Reporting. + +## Quick Start Examples + +### Data Binding and Looping +For detailed information on how to bind data sources and loop through data in reports, see: +**[Data Binding and Looping Documentation](../docs/DataBinding-and-Looping.md)** + +**[SimpleDataBindingExample.rdl](SimpleDataBindingExample.rdl)** - A minimal, well-commented example that demonstrates: +- How to define a DataSource and DataSet +- How to create a Table that loops through data rows +- How to bind Textboxes to data fields using `=Fields!FieldName.Value` +- Basic formatting and styling + +### Example Projects + +#### SampleApp2-SetData +Demonstrates how to programmatically set data to a report using DataTables. +- Shows database connection with SQLite +- Example of binding in-memory data to report datasets +- See `Form1.cs` for the implementation + +**Key Concepts:** +```csharp +// Load report +await rdlViewer1.SetSourceFile(new Uri(filepath)); + +// Bind data +await (await rdlViewer1.Report()).DataSets["Data"].SetData(dataTable); + +// Refresh view +await rdlViewer1.Rebuild(); +``` + +#### SqliteExamples +Contains various RDL files demonstrating: +- SimpleTest1.rdl - Basic table with data binding +- SimpleTest2.rdl - More complex report layouts +- SimpleTest3WithParameters.rdl - Reports with parameters +- chart.rdl - Chart examples +- barcode.rdl - Barcode generation + +#### JsonExamples +Examples of using JSON as a data provider + +#### SampleApp +Basic sample application showing report viewing + +#### Sample-Report-Viewer +Sample WinForms application for viewing reports + +#### SampleDesignerControl +Shows how to integrate the report designer control into your application + +## Common Patterns + +### 1. Looping Through Data with Tables + +In your RDL file, use a Table element: +```xml + + Data +
+ + + + + + + =Fields!FieldName.Value + + + + + + +
+
+``` + +The Details section automatically loops through each row in your dataset. + +### 2. Binding Data Sources + +**From Database (in RDL):** +```xml + + + + Microsoft.Data.Sqlite + Data Source=path/to/db.db + + + +``` + +**Programmatically (in C#):** +```csharp +DataTable dt = GetYourData(); +await (await rdlViewer.Report()).DataSets["DataSetName"].SetData(dt); +await rdlViewer.Rebuild(); +``` + +### 3. Using Textboxes + +**Static Textbox:** +```xml + + Report Title + +``` + +**Data-Bound Textbox (inside Table):** +```xml + + =Fields!ProductName.Value + +``` + +## Database File + +The `northwindEF.db` file in this directory is a sample SQLite database used by several examples. It contains standard Northwind sample data including: +- Categories +- Products +- Employees +- Orders +- And more... + +## Running the Examples + +1. Open the solution file in Visual Studio (Windows) +2. Build the solution +3. Run the desired example project +4. Most examples use the northwindEF.db database included in this directory + +## Additional Resources + +- [Full Data Binding Documentation](../docs/DataBinding-and-Looping.md) +- [Project Wiki](https://github.com/majorsilence/My-FyiReporting/wiki) +- [Database Providers Guide](https://github.com/majorsilence/My-FyiReporting/wiki/Database-Providers-Howto) +- [Main README](../Readme.md) diff --git a/Examples/SimpleDataBindingExample.rdl b/Examples/SimpleDataBindingExample.rdl new file mode 100644 index 00000000..8e648c78 --- /dev/null +++ b/Examples/SimpleDataBindingExample.rdl @@ -0,0 +1,292 @@ + + + Simple example demonstrating data binding and looping through textboxes + Majorsilence Reporting + 11in + 8.5in + + + + + + Microsoft.Data.Sqlite + Data Source=../northwindEF.db + + + + + + + + + DS1 + SELECT ProductID, ProductName, UnitPrice, UnitsInStock FROM Products LIMIT 10 + + + + ProductID + System.Int64 + + + ProductName + System.String + + + UnitPrice + System.Decimal + + + UnitsInStock + System.Int64 + + + + + + 7.5in + .25in + .25in + .25in + .25in + + + + .5in + + + .1in + .1in + 7in + .3in + Product List - Data Binding Example + + + + true + true + + + + + + + + Products + No products found! + + + + + + 1in + + + 3in + + + 1.5in + + + 1.5in + + + + +
+ + + 25pt + + + + + ID + + + + + + + + Product Name + + + + + + + + Unit Price + + + + + + + + In Stock + + + + + + + + true +
+ + + +
+ + + 20pt + + + + + + =Fields!ProductID.Value + + + + + + + + + + =Fields!ProductName.Value + true + + + + + + + + + + =Format(Fields!UnitPrice.Value, "C2") + + + + + + + + + + =Fields!UnitsInStock.Value + + + + + + + +
+
+
+ 3in + + + + + 0.5in + + + 5pt + 10pt + 12pt + 3in + =Globals!PageNumber + ' of ' + Globals!TotalPages + + + + true + true + +
diff --git a/Readme.md b/Readme.md index 4299acfa..f917b4c8 100644 --- a/Readme.md +++ b/Readme.md @@ -14,6 +14,9 @@ https://groups.google.com/d/forum/myfyireporting # Documentation See the [projects wiki](https://github.com/majorsilence/My-FyiReporting/wiki). +## Common Topics +- **[Data Binding and Looping Through Data](docs/DataBinding-and-Looping.md)** - Learn how to bind data sources and loop through data using textboxes and tables + # Download See the [downloads page](https://github.com/majorsilence/My-FyiReporting/wiki/Downloads). diff --git a/docs/DataBinding-and-Looping.md b/docs/DataBinding-and-Looping.md new file mode 100644 index 00000000..cd721974 --- /dev/null +++ b/docs/DataBinding-and-Looping.md @@ -0,0 +1,554 @@ +# Data Binding and Looping Through Data in Reports + +This guide explains how to bind data sources to reports and loop through data using textboxes and tables. + +## Table of Contents +- [Understanding Data Binding](#understanding-data-binding) +- [Binding Data Sources](#binding-data-sources) +- [Looping Through Data with Tables](#looping-through-data-with-tables) +- [Using Textboxes to Display Data](#using-textboxes-to-display-data) +- [Code Examples](#code-examples) + +## Understanding Data Binding + +Majorsilence Reporting uses RDL (Report Definition Language) files to define reports. Data binding connects your data source to report elements so they can display dynamic data. + +### Key Components: +- **DataSource**: Defines the connection to your database or data provider +- **DataSet**: Contains a query and defines the fields available for binding +- **Fields**: Individual data columns that can be bound to report elements +- **Report Items**: Visual elements (Textboxes, Tables, etc.) that display the data + +## Binding Data Sources + +### Method 1: Database Connection (RDL Definition) + +In your RDL file, define a DataSource and DataSet: + +```xml + + + + Microsoft.Data.Sqlite + Data Source=/path/to/database.db + + + + + + + + DS1 + SELECT CategoryID, CategoryName, Description FROM Categories + + + + CategoryID + System.Int64 + + + CategoryName + System.String + + + Description + System.String + + + + +``` + +### Method 2: Programmatic Data Binding (C#) + +You can also set data programmatically in your application: + +```csharp +using System.Data; +using Majorsilence.Reporting.RdlViewer; + +// Load the report +string filepath = "path/to/report.rdl"; +await rdlViewer1.SetSourceFile(new Uri(filepath)); + +// Create or retrieve your data +DataTable dt = new DataTable(); +dt.Columns.Add("CategoryID", typeof(int)); +dt.Columns.Add("CategoryName", typeof(string)); +dt.Columns.Add("Description", typeof(string)); + +// Add sample data +dt.Rows.Add(1, "Beverages", "Soft drinks, coffees, teas"); +dt.Rows.Add(2, "Condiments", "Sweet and savory sauces"); + +// Bind data to the dataset +await (await rdlViewer1.Report()).DataSets["Data"].SetData(dt); +await rdlViewer1.Rebuild(); +``` + +### Method 3: Using RdlCreator to Generate Reports + +```csharp +using Majorsilence.Reporting.RdlCreator; + +// Initialize configuration (once per app instance) +RdlEngineConfig.RdlEngineConfigInit(); + +string dataProvider = "Microsoft.Data.Sqlite"; +string connectionString = "Data Source=/path/to/database.db"; +string query = "SELECT CategoryID, CategoryName, Description FROM Categories"; + +var create = new Majorsilence.Reporting.RdlCreator.Create(); +var report = await create.GenerateRdl( + dataProvider, + connectionString, + query, + pageHeaderText: "My Report Title" +); + +// Generate PDF +string filepath = "output.pdf"; +var ofs = new Majorsilence.Reporting.Rdl.OneFileStreamGen(filepath, true); +await report.RunGetData(null); +await report.RunRender(ofs, Majorsilence.Reporting.Rdl.OutputPresentationType.PDF); +``` + +## Looping Through Data with Tables + +To loop through data and display multiple rows, you use a **Table** element with a **Details** section. Each textbox in the Details section will be repeated for every row in your dataset. + +### Basic Table Structure + +```xml + + Data + Query returned no rows! + + + 1.5in + + + 2in + + + + +
+ + + 12pt + + + + + Category ID + + + + + + + + Category Name + + + + + + + +
+ + +
+ + + 12pt + + + + + =Fields!CategoryID.Value + + + + + + + =Fields!CategoryName.Value + + + + + + +
+
+``` + +### How It Works: +1. The `Data` tells the table which dataset to use +2. The `
` section defines column headers (displayed once) +3. The `
` section defines the row template that repeats for each data row +4. Each textbox in the Details section uses `=Fields!FieldName.Value` to bind to data + +## Using Textboxes to Display Data + +### Simple Textbox (Non-Repeating) + +For displaying a single value (like in a page header or footer): + +```xml + + .1in + .1in + 6in + .25in + My Report Title + + +``` + +### Data-Bound Textbox (Inside Table) + +For displaying values that repeat with data: + +```xml + + =Fields!CategoryName.Value + true + + +``` + +### Using Expressions + +Textboxes support expressions for formatting and calculations: + +```xml + +=Fields!FirstName.Value & " " & Fields!LastName.Value + + +=Format(Fields!Price.Value, "C2") + + +=Format(Fields!OrderDate.Value, "yyyy-MM-dd") + + +=IIF(Fields!Quantity.Value > 100, "High", "Low") + + +=Fields!Price.Value * Fields!Quantity.Value +``` + +## Code Examples + +### Complete Example: Database to PDF + +```csharp +using System; +using System.Threading.Tasks; +using Majorsilence.Reporting.RdlCreator; + +namespace ReportExample +{ + class Program + { + static async Task Main(string[] args) + { + // Initialize once per application + RdlEngineConfig.RdlEngineConfigInit(); + + // Database connection + string connectionString = "Data Source=northwind.db"; + string query = @" + SELECT + CategoryID, + CategoryName, + Description + FROM Categories"; + + // Create report + var creator = new Majorsilence.Reporting.RdlCreator.Create(); + var report = await creator.GenerateRdl( + "Microsoft.Data.Sqlite", + connectionString, + query, + pageHeaderText: "Categories Report" + ); + + // Generate PDF + string outputPath = "categories.pdf"; + var fileStream = new Majorsilence.Reporting.Rdl.OneFileStreamGen( + outputPath, + true + ); + + await report.RunGetData(null); + await report.RunRender( + fileStream, + Majorsilence.Reporting.Rdl.OutputPresentationType.PDF + ); + + Console.WriteLine($"Report generated: {outputPath}"); + } + } +} +``` + +### Example: In-Memory Data + +```csharp +using System; +using System.Data; +using System.Threading.Tasks; +using System.Windows.Forms; +using Majorsilence.Reporting.RdlViewer; + +public partial class ReportForm : Form +{ + private RdlViewer rdlViewer1; + + public ReportForm() + { + InitializeComponent(); + rdlViewer1 = new RdlViewer(); + rdlViewer1.Dock = DockStyle.Fill; + this.Controls.Add(rdlViewer1); + } + + private async void LoadReport() + { + // Create in-memory data + DataTable categories = new DataTable("Categories"); + categories.Columns.Add("CategoryID", typeof(int)); + categories.Columns.Add("CategoryName", typeof(string)); + categories.Columns.Add("Description", typeof(string)); + + categories.Rows.Add(1, "Beverages", "Soft drinks, coffees, teas, beers"); + categories.Rows.Add(2, "Condiments", "Sweet and savory sauces, relishes"); + categories.Rows.Add(3, "Confections", "Desserts, candies, and sweet breads"); + categories.Rows.Add(4, "Dairy Products", "Cheeses"); + + // Load report definition + string reportPath = "path/to/report.rdl"; + await rdlViewer1.SetSourceFile(new Uri(reportPath)); + + // Bind data to dataset + var report = await rdlViewer1.Report(); + await report.DataSets["Data"].SetData(categories); + + // Refresh display + await rdlViewer1.Rebuild(); + } +} +``` + +### Example: Using Multiple Datasets + +```xml + + + + + DS1 + SELECT * FROM Categories + + + + + + DS1 + SELECT * FROM Products + + + + + + + + + Categories + +
+ + + + Products + +
+
+ +``` + +```csharp +// Bind multiple datasets programmatically +await rdlViewer1.SetSourceFile(new Uri(reportPath)); +var report = await rdlViewer1.Report(); + +DataTable categories = GetCategoriesData(); +DataTable products = GetProductsData(); + +await report.DataSets["Categories"].SetData(categories); +await report.DataSets["Products"].SetData(products); + +await rdlViewer1.Rebuild(); +``` + +## Common Scenarios + +### Scenario 1: Master-Detail Report + +Use nested tables or filters to show related data: + +```xml + + + Categories +
+ + + + + + +
+ Products + + + =Fields!CategoryID.Value + Equal + + =Fields!CategoryID.Value + + + + +
+ + + + + +
+ +``` + +### Scenario 2: Grouped Data + +```xml + + Data + + + + + =Fields!CategoryName.Value + + +
+ + + + + + + =Fields!CategoryName.Value + + + + + + + +
+
+
+ +
+``` + +### Scenario 3: Conditional Formatting + +```xml + + =Fields!Status.Value + + +``` + +## Best Practices + +1. **Use Meaningful Names**: Give your DataSets, Tables, and Textboxes descriptive names +2. **Set CanGrow**: For text fields that might be long, set `true` to allow expansion +3. **Handle Null Values**: Use `IsNothing()` function to check for null values +4. **Optimize Queries**: Only select the fields you need in your SQL queries +5. **Use Parameters**: For dynamic reports, use report parameters to filter data +6. **Test with Real Data**: Always test reports with actual data to ensure proper formatting + +## Supported Data Providers + +Majorsilence Reporting supports various data providers: +- Microsoft.Data.Sqlite +- Microsoft.Data.SqlClient +- MySQL.NET +- PostgreSQL +- Firebird.NET 2.0 +- JSON (via JSON data provider) +- In-memory DataTables + +## Additional Resources + +- [Project Wiki](https://github.com/majorsilence/My-FyiReporting/wiki) +- [Examples Directory](../Examples/) - Contains working examples +- [Database Providers Guide](https://github.com/majorsilence/My-FyiReporting/wiki/Database-Providers-Howto) +- [Main README](../Readme.md) + +## Troubleshooting + +### Issue: "Query returned no rows!" +- Verify your connection string is correct +- Check that the database file exists at the specified path +- Ensure your query syntax is valid for your database +- Test the query directly in a database tool + +### Issue: Fields not displaying data +- Verify field names match between DataSet definition and textbox binding +- Check that the DataSetName in your Table matches the DataSet Name +- Ensure data types in Field definitions match actual data + +### Issue: Report not updating with new data +- Make sure to call `await rdlViewer1.Rebuild()` after setting data +- Verify the dataset name matches between RDL and code + +## Summary + +To loop through data in reports: +1. Define a **DataSet** with your query and fields +2. Create a **Table** element and set its **DataSetName** +3. Add **Textboxes** in the **Details** section using `=Fields!FieldName.Value` +4. Bind data either through: + - Database connection in RDL + - Programmatically using `DataSets["Name"].SetData(dataTable)` + - Using RdlCreator to generate reports from queries + +The Table's Details section automatically loops through all rows in your dataset, creating a textbox for each row with the bound data.