4

Good Afternoon All,

I've spent the best part of the last 2 weeks searching for help on the issue I'm having with my C# WinForm application.

I have a form which has a DataGridView displaying details pulled from a database. When the user double-clicks a row in this grid, the code grabs the value from the CustomerID column, puts it into a static public string, then opens another form which has a reportviewer.

What I'm trying to do then is to get the reportviewer to run a report, using the CustomerID as a parameter.

So far all I've managed to do is get it to state that the report definition has not been specified.

My SQL server is an old server which does not have SSRS, and I can't install it due to change request issues, so I'm having to use a Local Report, not a Server Report.

The way I created the report was to go to my Solution Explorer in Visual Studio, and go to Add - New Item - Report, which I then gave a dataset and a parameter. I put the report in a subfolder called Reports, which sits within the solution next to all my forms.

The code for my reportviewer form is as below. Don't laugh too much, I'm 100% self taught.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Reporting.WinForms;
using System.Data.SqlClient;

namespace FormsApp
{
public partial class ReportGenerator : Form
{
    public ReportGenerator()
    {
        InitializeComponent();
        this.reportViewer1.RefreshReport();
    }

    private void ReportGenerator_Load(object sender, EventArgs e)
    {
        if (CustomerList.CustomerID!= "")
        {
            this.reportViewer1.ProcessingMode = ProcessingMode.Local;
            this.reportViewer1.LocalReport.ReportPath = "\\Reports\\CustomerDetails.rdlc";
            this.reportViewer1.ShowParameterPrompts = true;
            ReportParameter CustID = new ReportParameter("CustomerID",CustomerList.CustomerID);
            this.reportViewer1.LocalReport.SetParameters(CustID);
        }
        else
        {}

    }
    }
}

Am I using the LocalReport incorrectly? I'm really stumped and this is the last bit I need to get working then my application is complete.

Any help would be greatly appreciated.

Many thanks

UPDATE

My code now shows as below following suggestions from various sources.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Reporting.WinForms;
using System.Data.SqlClient;

namespace FormsApp
{
    public partial class ReportGenerator : Form
    {
    public ReportGenerator()
    {
        InitializeComponent();
        this.reportViewer1.RefreshReport();
    }

    private DataTable getCustomerData()
    {
        SqlConnection con = new SqlConnection(Home.ConString);
        DataSet ds = new DataSet();
        ds.DataSetName = "CustomerListRetrieve";
        string sql = "SELECT * FROM Customers";
        SqlDataAdapter da = new SqlDataAdapter(sql, con);
        da.Fill(ds);
        DataTable dt = ds.Tables[0];
        return dt;
    }

    private void ReportGenerator_Load(object sender, EventArgs e)
    {
        if (CustomerList.CustomerID != "")
        {
            this.reportViewer1.Reset();
            this.reportViewer1.LocalReport.ReportEmbeddedResource = "FormsApp.Reports.CustomerDetails.rdlc";
            ReportDataSource rds = new ReportDataSource("CustomerListRetrieve", getCustomerData());
            this.reportViewer1.LocalReport.DataSources.Clear();
            this.reportViewer1.LocalReport.DataSources.Add(rds);
            ReportParameter CustID= new ReportParameter("CustomerID", CustomerList.CustomerID);
            this.reportViewer1.LocalReport.SetParameters(CustID);
            this.reportViewer1.LocalReport.Refresh();
            ViewButtonClicked();
        }
        else
        {}
    }

    private void ViewButtonClicked(object sender, ReportParametersEventArgs e)
    {
        var SubmittedParameters = e.Parameters.Clone();
        e.Parameters.Clear();
        SubmittedParameters.Where(x => x.Name == "Parametername").FirstOrDefault().Values[0] = "YourValue";
        SubmittedParameters.ToList().ForEach(x => e.Parameters.Add(x));
    }
    private void OnReportChosenFromList()
    {
        reportViewer1.SubmittingParameterValues -= ViewButtonClicked;
        reportViewer1.SubmittingParameterValues += ViewButtonClicked;
    }
  }
}

The datasource code I added following the response from codingbiz. After adding this, I no longer got the report definition error, just a blank window when the reportviewer loaded.

The bottom two methods - ViewButtonClicked and OnReportChosenFromList were added following the suggestion from Bernard Walters. After adding this I get 2 errors stating:

  1. Error 1 Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement.
  2. Microsoft.Reporting.WinForms.ReportParameterCollection does not contain a definition for 'Clone' and no extension method 'Clone'...

Really stumped now. Probably implemented the suggestions wrong.

Osama Rizwan
  • 615
  • 1
  • 7
  • 19
Tom Camish
  • 69
  • 1
  • 1
  • 10

3 Answers3

0

I've had the same problem, here is the fix:

private void ViewButtonClicked(object sender, ReportParametersEventArgs e)
{
    var SubmittedParameters = e.Parameters.Clone();
    e.Parameters.Clear();
    SubmittedParameters.Where(x => x.Name == "Parametername").FirstOrDefault().Values[0] = "YourValue";
    SubmittedParameters.ToList().ForEach(x => e.Parameters.Add(x));
}

private void OnReportChosenFromList()
{
    reportViewer.SubmittingParameterValues -= ViewButtonClicked;
    reportViewer.SubmittingParameterValues += ViewButtonClicked;
}

This line:

reportViewer.SubmittingParameterValues += ViewButtonClicked;

sets a listener on the reportviewer that executes ViewButtonClicked when the event is triggered.

ViewButtonClicked then intercepts the message containing all the parameter data that is being sent to SSRS, which allows you to copy its data, edit it and then add the data again just before the message is sent to SSRS.

NOTE: This has been edited a bit, but most of it is copied straight out of my code

croxy
  • 4,082
  • 9
  • 28
  • 46
Bernard Walters
  • 391
  • 1
  • 4
  • 16
  • The way the reportviewer works makes it nearly impossible to change the values you see, but you sure has heck can change the values SSRS sees ;) – Bernard Walters Feb 28 '17 at 15:44
  • Thank you for your reply. I'm not sure how to add your code to mine. Can the code within the ViewButtonClicked method be added to my ReportGenerator_Load method? Thanks, – Tom Camish Mar 01 '17 at 15:20
  • @TomCamish yes, i would added it to the method that instantiates when you change/view reports. PLEASE note that you have to keep both the -= and the +=...without them you would create multiple event handlers and it would result int then method being executed +1 time for every time you view a new report. – Bernard Walters Mar 01 '17 at 15:28
  • I've tried adding it and getting an error "System.EventArgs does not contain a definition for Parameters". Sorry to be a bit slow with this (self taught) - how can I implement this into my code? – Tom Camish Mar 01 '17 at 15:37
  • are you using the event ReportParametersEventArgs? – Bernard Walters Mar 01 '17 at 15:41
  • make sure everything is exactly as seen above...it needs to be reportviewer.SubmittingParameterValues(the correct event would then automatically be ReportParametersEventArgs ) – Bernard Walters Mar 01 '17 at 15:43
  • Thank you - I have updated the question showing the most recent code. – Tom Camish Mar 01 '17 at 15:59
  • @TomCamish you're doing it wrong, add OnReportChosenFromList() to the start of the ReportGenerator()...you never have to execute ViewButtonClicked() because it is automatically executed on the event...thats why you add the eventhandler inside OnReportChosenFromList() – Bernard Walters Mar 01 '17 at 16:39
0

The reportViewer will not act until you have reportViewer1.RefreshReport(); this is the command for it to run the report locally or remotely. Every time you wan the report to refresh or initially load you need this command.

Jake
  • 1
0

I have written an entire wrapper class for reporting and can help / offer parts of it, but can do that later / chat / email.

As for the issue, you dont have a report data source provided anywhere that the report actually runs against. You have a query against your database that returns a dataset which is good, but it is not explicitly tied to the report. So, let me start this way.

When doing your query and calling FILL(), you can fill to a single DataTable instead of a DataSet. The advantage of a DataSet is that you can then pass multiple tables to a report and have for more parent/child reporting... or even having an additional table for nothing but a single record to have things like captions, titles, messages that you want elsewhere in your report that will always be the same thing vs copying on every row of every table. For now, lets stick to just the single DataTable

private void generateReport()
{
   var rptDT = getCustomerData();
   // dont know how you are preparing the load of your report...
   var yourRpt = YourReportViewer.LocalReport.LoadReportDefinition( whateverYourReport );

   // Now, add the data source to it.  THIS is what populates the report with the data
   // as a result of your query, pull down, assign table name for context in the report.
   // You are telling the local report, here is the datasource, and by the way, the named
   // reference of the table is whatever you set for the table name... and finally, this
   // datatable object IS the content for the report.
   YourReportViewer.LocalReport.DataSources.Add(
      new ReportDataSource( rptDT.TableName, rptDT ) );
}

private DataTable getCustomerData()
{
   SqlConnection con = new SqlConnection(Home.ConString);
   // slightly altered using just a datatable
   DataTable dt = new DataTable();
   string sql = "SELECT * FROM Customers";
   SqlDataAdapter da = new SqlDataAdapter(sql, con);
   da.Fill(dt);
   dt.TableName = "CustomerList";
   return dt;
}

Again, I could offer more, but it would be too much for just this one question as you would probably have/want more back/forth questions.

DRapp
  • 47,638
  • 12
  • 72
  • 142