如何手动绑定Report Viewer?通过代码实现数据库绑定及表名输入展示报表
Got it, let's break down how to bind a ReportViewer to a database table dynamically—no wizard required. The goal is to let users type a table name into a TextBox, then load and display that table's data in the ReportViewer. I'll cover WinForms and ASP.NET Web Forms implementations since those are the most common use cases, with full code examples and key best practices.
WinForms Implementation
Step 1: Set Up Your Form
First, add these controls to your WinForm:
TextBox(name:txtTableName) for inputting the table nameButton(name:btnLoadReport) to trigger the report loadReportViewer(name:reportViewer1) to display the data
Step 2: Add Required Namespaces
At the top of your form's code file, include these:
using System.Data; using System.Data.SqlClient; using System.IO; using System.Configuration; using Microsoft.Reporting.WinForms;
Step 3: Configure Database Connection
Add your connection string to App.config:
<connectionStrings> <add name="MyDbConnection" connectionString="Data Source=YOUR_SERVER_NAME;Initial Catalog=YOUR_DATABASE_NAME;Integrated Security=True;" providerName="System.Data.SqlClient" /> </connectionStrings>
Replace YOUR_SERVER_NAME and YOUR_DATABASE_NAME with your actual database details.
Step 4: Full Form Code
Here's the complete code to handle dynamic data loading and report generation:
public partial class DynamicReportForm : Form { private readonly string _connectionString = ConfigurationManager.ConnectionStrings["MyDbConnection"].ConnectionString; public DynamicReportForm() { InitializeComponent(); // Initialize ReportViewer to use local processing reportViewer1.ProcessingMode = ProcessingMode.Local; } private void btnLoadReport_Click(object sender, EventArgs e) { string tableName = txtTableName.Text.Trim(); if (string.IsNullOrEmpty(tableName)) { MessageBox.Show("Please enter a table name!", "Input Required", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } try { // Validate the table exists first (prevents SQL injection and invalid inputs) if (!TableExists(tableName)) { MessageBox.Show("Table does not exist in the database!", "Invalid Table", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Fetch data from the specified table DataTable tableData = GetTableData(tableName); // Generate a dynamic RDLC report definition string rdlcContent = GenerateDynamicRdlc(tableData); // Load the RDLC into ReportViewer reportViewer1.LocalReport.LoadReportDefinition(new StringReader(rdlcContent)); // Bind the data to the report ReportDataSource dataSource = new ReportDataSource("DataSet1", tableData); reportViewer1.LocalReport.DataSources.Clear(); reportViewer1.LocalReport.DataSources.Add(dataSource); // Refresh the report to display data reportViewer1.RefreshReport(); } catch (Exception ex) { MessageBox.Show($"Error loading report: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // Check if the table exists in the database private bool TableExists(string tableName) { using (SqlConnection conn = new SqlConnection(_connectionString)) { string query = "SELECT COUNT(*) FROM sys.tables WHERE name = @TableName"; SqlCommand cmd = new SqlCommand(query, conn); cmd.Parameters.AddWithValue("@TableName", tableName); conn.Open(); int count = (int)cmd.ExecuteScalar(); return count > 0; } } // Fetch all data from the specified table private DataTable GetTableData(string tableName) { DataTable dt = new DataTable(tableName); using (SqlConnection conn = new SqlConnection(_connectionString)) { // Use square brackets to handle table names with spaces/special characters string query = $"SELECT * FROM [{tableName}]"; SqlDataAdapter adapter = new SqlDataAdapter(query, conn); adapter.Fill(dt); } return dt; } // Generate a dynamic RDLC report with columns matching the table private string GenerateDynamicRdlc(DataTable dt) { // Build the RDLC XML structure string rdlc = $@"<?xml version=""1.0"" encoding=""utf-8""?> <Report xmlns=""http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition"" xmlns:rd=""http://schemas.microsoft.com/SQLServer/reporting/reportdesigner""> <DataSources> <DataSource Name=""DataSet1""> <ConnectionProperties> <DataProvider>SQL</DataProvider> <ConnectString/> </ConnectionProperties> <rd:DataSourceID>00000000-0000-0000-0000-000000000000</rd:DataSourceID> </DataSource> </DataSources> <DataSets> <DataSet Name=""DataSet1""> <Query> <DataSourceName>DataSet1</DataSourceName> <CommandText>SELECT * FROM [{dt.TableName}]</CommandText> </Query> <Fields>"; // Add fields for each column in the table foreach (DataColumn col in dt.Columns) { rdlc += $@" <Field Name=""{col.ColumnName}""> <DataField>{col.ColumnName}</DataField> <rd:TypeName>{MapDataType(col.DataType)}</rd:TypeName> </Field>"; } rdlc += @" </Fields> </DataSet> </DataSets> <Body> <ReportItems> <Tablix Name=""Table1""> <TablixBody> <TablixColumns>"; // Add columns to the table foreach (DataColumn col in dt.Columns) { rdlc += $@" <TablixColumn> <Width>1.5in</Width> </TablixColumn>"; } rdlc += @" </TablixColumns> <TablixRows> <!-- Header Row --> <TablixRow> <Height>0.25in</Height> <TablixCells>"; // Add header cells foreach (DataColumn col in dt.Columns) { rdlc += $@" <TablixCell> <CellContents> <Textbox Name=""{col.ColumnName}_Header""> <Paragraphs> <Paragraph> <TextRuns> <TextRun> <Value>{col.ColumnName}</Value> <Style><FontWeight>Bold</FontWeight></Style> </TextRun> </TextRuns> </Paragraph> </Paragraphs> <Style><Border><Style>Solid</Style><Color>LightGray</Color></Border><Padding>2pt</Padding></Style> </Textbox> </CellContents> </TablixCell>"; } rdlc += @" </TablixCells> </TablixRow> <!-- Data Row --> <TablixRow> <Height>0.25in</Height> <TablixCells>"; // Add data cells foreach (DataColumn col in dt.Columns) { rdlc += $@" <TablixCell> <CellContents> <Textbox Name=""{col.ColumnName}""> <Paragraphs> <Paragraph> <TextRuns> <TextRun> <Value>=Fields!{col.ColumnName}.Value</Value> </TextRun> </TextRuns> </Paragraph> </Paragraphs> <Style><Border><Style>Solid</Style><Color>LightGray</Color></Border><Padding>2pt</Padding></Style> </Textbox> </CellContents> </TablixCell>"; } rdlc += @" </TablixCells> </TablixRow> </TablixRows> </TablixBody> <TablixColumnHierarchy> <TablixMembers>"; foreach (DataColumn col in dt.Columns) { rdlc += $@" <TablixMember> <KeepWithGroup>After</KeepWithGroup> </TablixMember>"; } rdlc += @" </TablixMembers> </TablixColumnHierarchy> <TablixRowHierarchy> <TablixMembers> <TablixMember> <Group Name=""HeaderGroup"" /> <TablixHeader> <Size>0.3in</Size> <CellContents> <Textbox Name=""ReportTitle""> <Paragraphs> <Paragraph> <TextRuns> <TextRun> <Value>{dt.TableName} Data</Value> <Style><FontSize>14pt</FontSize><FontWeight>Bold</FontWeight></Style> </TextRun> </TextRuns> </Paragraph> </Paragraphs> </Textbox> </CellContents> </TablixHeader> </TablixMember> <TablixMember> <Group Name=""DetailsGroup""> <GroupExpressions></GroupExpressions> </Group> </TablixMember> </TablixMembers> </TablixRowHierarchy> <Top>0.25in</Top> <Left>0.25in</Left> <Width>" + (dt.Columns.Count * 1.5) + @"in</Width> </Tablix> </ReportItems> <Height>" + (dt.Rows.Count > 0 ? 0.5 + (dt.Rows.Count * 0.25) : 1) + @"in</Height> </Body> <Width>" + (dt.Columns.Count * 1.5 + 0.5) + @"in</Width> <Page> <PageHeight>8.5in</PageHeight> <PageWidth>11in</PageWidth> <Margins> <Left>0.5in</Left> <Right>0.5in</Right> <Top>0.5in</Top> <Bottom>0.5in</Bottom> </Margins> </Page> </Report>"; return rdlc; } // Map .NET data types to RDLC-compatible types private string MapDataType(Type dataType) { if (dataType == typeof(int)) return "System.Int32"; if (dataType == typeof(string)) return "System.String"; if (dataType == typeof(DateTime)) return "System.DateTime"; if (dataType == typeof(decimal)) return "System.Decimal"; if (dataType == typeof(bool)) return "System.Boolean"; // Add more mappings as needed for your database types return "System.String"; } }
ASP.NET Web Forms Implementation
Step 1: Set Up Your Page
Add this markup to your ASPX page:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="DynamicReport.aspx.cs" Inherits="YourProjectNamespace.DynamicReport" %> <%@ Register Assembly="Microsoft.ReportViewer.WebForms" Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Dynamic Table Report</title> </head> <body> <form id="form1" runat="server"> <div style="margin: 20px;"> <asp:TextBox ID="txtTableName" runat="server" placeholder="Enter table name" style="padding: 8px; width: 250px;"></asp:TextBox> <asp:Button ID="btnLoadReport" runat="server" Text="Load Report" OnClick="btnLoadReport_Click" style="padding: 8px 16px; margin-left: 10px;" /> <hr /> <rsweb:ReportViewer ID="ReportViewer1" runat="server" Width="100%" Height="600px" /> </div> </form> </body> </html>
Step 2: Backend Code
Most of the logic is similar to WinForms—here's the code-behind:
using System.Data; using System.Data.SqlClient; using System.IO; using System.Web.Configuration; using Microsoft.Reporting.WebForms; namespace YourProjectNamespace { public partial class DynamicReport : System.Web.UI.Page { private readonly string _connectionString = WebConfigurationManager.ConnectionStrings["MyDbConnection"].ConnectionString; protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { ReportViewer1.ProcessingMode = ProcessingMode.Local; } } protected void btnLoadReport_Click(object sender, EventArgs e) { string tableName = txtTableName.Text.Trim(); if (string.IsNullOrEmpty(tableName)) { ShowAlert("Please enter a table name!"); return; } try { if (!TableExists(tableName)) { ShowAlert("Table does not exist in the database!"); return; } DataTable tableData = GetTableData(tableName); string rdlcContent = GenerateDynamicRdlc(tableData); ReportViewer1.LocalReport.LoadReportDefinition(new StringReader(rdlcContent)); ReportDataSource dataSource = new ReportDataSource("DataSet1", tableData); ReportViewer1.LocalReport.DataSources.Clear(); ReportViewer1.LocalReport.DataSources.Add(dataSource); ReportViewer1.LocalReport.Refresh(); } catch (Exception ex) { ShowAlert($"Error loading report: {ex.Message}"); } } private void ShowAlert(string message) { ClientScript.RegisterStartupScript(GetType(), "alert", $"alert('{message.Replace("'", "\\'")}');", true); } // Reuse the helper methods from the WinForms code private bool TableExists(string tableName) { // Same as WinForms implementation } private DataTable GetTableData(string tableName) { // Same as WinForms implementation } private string GenerateDynamicRdlc(DataTable dt) { // Same as WinForms implementation } private string MapDataType(Type dataType) { // Same as WinForms implementation } } }
Key Notes & Best Practices
- Security First: Always validate the table name exists before executing queries (we do this with the
TableExistsmethod) to prevent SQL injection. Never trust raw user input directly in queries. - Database Permissions: Use a database user with only read access to the tables users should be able to view—minimize permissions to reduce risk.
- Data Type Mapping: Extend the
MapDataTypemethod if you use less common data types (likefloat,byte[], etc.) in your tables. - Error Handling: Add more specific error handling based on your needs (e.g., handle connection failures separately from invalid table names).
内容的提问来源于stack exchange,提问作者Chrollo Lucifer

